Blender  V3.3
FN_multi_function_procedure_test.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0 */
2 
3 #include "testing/testing.h"
4 
9 
10 namespace blender::fn::tests {
11 
12 TEST(multi_function_procedure, ConstantOutput)
13 {
21  CustomMF_Constant<int> constant_fn{5};
22  CustomMF_SI_SI_SO<int, int, int> add_fn{"Add", [](int a, int b) { return a + b; }};
23 
24  MFProcedure procedure;
25  MFProcedureBuilder builder{procedure};
26 
27  auto [var1] = builder.add_call<1>(constant_fn);
28  auto [var2] = builder.add_call<1>(add_fn, {var1, var1});
29  builder.add_destruct(*var1);
30  builder.add_return();
31  builder.add_output_parameter(*var2);
32 
33  EXPECT_TRUE(procedure.validate());
34 
35  MFProcedureExecutor executor{procedure};
36 
37  MFParamsBuilder params{executor, 2};
39 
40  Array<int> output_array(2);
41  params.add_uninitialized_single_output(output_array.as_mutable_span());
42 
43  executor.call(IndexRange(2), params, context);
44 
45  EXPECT_EQ(output_array[0], 10);
46  EXPECT_EQ(output_array[1], 10);
47 }
48 
49 TEST(multi_function_procedure, SimpleTest)
50 {
59  CustomMF_SI_SI_SO<int, int, int> add_fn{"add", [](int a, int b) { return a + b; }};
60  CustomMF_SM<int> add_10_fn{"add_10", [](int &a) { a += 10; }};
61 
62  MFProcedure procedure;
63  MFProcedureBuilder builder{procedure};
64 
65  MFVariable *var1 = &builder.add_single_input_parameter<int>();
66  MFVariable *var2 = &builder.add_single_input_parameter<int>();
67  auto [var3] = builder.add_call<1>(add_fn, {var1, var2});
68  auto [var4] = builder.add_call<1>(add_fn, {var2, var3});
69  builder.add_call(add_10_fn, {var4});
70  builder.add_destruct({var1, var2, var3});
71  builder.add_return();
72  builder.add_output_parameter(*var4);
73 
74  EXPECT_TRUE(procedure.validate());
75 
76  MFProcedureExecutor executor{procedure};
77 
78  MFParamsBuilder params{executor, 3};
80 
81  Array<int> input_array = {1, 2, 3};
82  params.add_readonly_single_input(input_array.as_span());
83  params.add_readonly_single_input_value(3);
84 
85  Array<int> output_array(3);
86  params.add_uninitialized_single_output(output_array.as_mutable_span());
87 
88  executor.call(IndexRange(3), params, context);
89 
90  EXPECT_EQ(output_array[0], 17);
91  EXPECT_EQ(output_array[1], 18);
92  EXPECT_EQ(output_array[2], 19);
93 }
94 
95 TEST(multi_function_procedure, BranchTest)
96 {
109  CustomMF_SM<int> add_10_fn{"add_10", [](int &a) { a += 10; }};
110  CustomMF_SM<int> add_100_fn{"add_100", [](int &a) { a += 100; }};
111 
112  MFProcedure procedure;
113  MFProcedureBuilder builder{procedure};
114 
115  MFVariable *var1 = &builder.add_single_mutable_parameter<int>();
116  MFVariable *var2 = &builder.add_single_input_parameter<bool>();
117 
118  MFProcedureBuilder::Branch branch = builder.add_branch(*var2);
119  branch.branch_false.add_call(add_10_fn, {var1});
120  branch.branch_true.add_call(add_100_fn, {var1});
121  builder.set_cursor_after_branch(branch);
122  builder.add_call(add_10_fn, {var1});
123  builder.add_destruct({var2});
124  builder.add_return();
125 
126  EXPECT_TRUE(procedure.validate());
127 
128  MFProcedureExecutor procedure_fn{procedure};
129  MFParamsBuilder params(procedure_fn, 5);
130 
131  Array<int> values_a = {1, 5, 3, 6, 2};
132  Array<bool> values_cond = {true, false, true, true, false};
133 
134  params.add_single_mutable(values_a.as_mutable_span());
135  params.add_readonly_single_input(values_cond.as_span());
136 
138  procedure_fn.call({1, 2, 3, 4}, params, context);
139 
140  EXPECT_EQ(values_a[0], 1);
141  EXPECT_EQ(values_a[1], 25);
142  EXPECT_EQ(values_a[2], 113);
143  EXPECT_EQ(values_a[3], 116);
144  EXPECT_EQ(values_a[4], 22);
145 }
146 
147 TEST(multi_function_procedure, EvaluateOne)
148 {
155  int tot_evaluations = 0;
156  CustomMF_SI_SO<int, int> add_10_fn{"add_10", [&](int a) {
157  tot_evaluations++;
158  return a + 10;
159  }};
160 
161  MFProcedure procedure;
162  MFProcedureBuilder builder{procedure};
163 
164  MFVariable *var1 = &builder.add_single_input_parameter<int>();
165  auto [var2] = builder.add_call<1>(add_10_fn, {var1});
166  builder.add_destruct(*var1);
167  builder.add_return();
168  builder.add_output_parameter(*var2);
169 
170  MFProcedureExecutor procedure_fn{procedure};
171  MFParamsBuilder params{procedure_fn, 5};
172 
173  Array<int> values_out = {1, 2, 3, 4, 5};
174  params.add_readonly_single_input_value(1);
175  params.add_uninitialized_single_output(values_out.as_mutable_span());
176 
178  procedure_fn.call({0, 1, 3, 4}, params, context);
179 
180  EXPECT_EQ(values_out[0], 11);
181  EXPECT_EQ(values_out[1], 11);
182  EXPECT_EQ(values_out[2], 3);
183  EXPECT_EQ(values_out[3], 11);
184  EXPECT_EQ(values_out[4], 11);
185  /* We expect only one evaluation, because the input is constant. */
186  EXPECT_EQ(tot_evaluations, 1);
187 }
188 
189 TEST(multi_function_procedure, SimpleLoop)
190 {
206  CustomMF_Constant<int> const_1_fn{1};
207  CustomMF_Constant<int> const_0_fn{0};
208  CustomMF_SI_SI_SO<int, int, bool> greater_or_equal_fn{"greater or equal",
209  [](int a, int b) { return a >= b; }};
210  CustomMF_SM<int> double_fn{"double", [](int &a) { a *= 2; }};
211  CustomMF_SM<int> add_1000_fn{"add 1000", [](int &a) { a += 1000; }};
212  CustomMF_SM<int> add_1_fn{"add 1", [](int &a) { a += 1; }};
213 
214  MFProcedure procedure;
215  MFProcedureBuilder builder{procedure};
216 
217  MFVariable *var_count = &builder.add_single_input_parameter<int>("count");
218  auto [var_out] = builder.add_call<1>(const_1_fn);
219  var_out->set_name("out");
220  auto [var_index] = builder.add_call<1>(const_0_fn);
221  var_index->set_name("index");
222 
223  MFProcedureBuilder::Loop loop = builder.add_loop();
224  auto [var_condition] = builder.add_call<1>(greater_or_equal_fn, {var_index, var_count});
225  var_condition->set_name("condition");
226  MFProcedureBuilder::Branch branch = builder.add_branch(*var_condition);
227  branch.branch_true.add_destruct(*var_condition);
228  branch.branch_true.add_loop_break(loop);
229  branch.branch_false.add_destruct(*var_condition);
230  builder.set_cursor_after_branch(branch);
231  builder.add_call(double_fn, {var_out});
232  builder.add_call(add_1_fn, {var_index});
233  builder.add_loop_continue(loop);
234  builder.set_cursor_after_loop(loop);
235  builder.add_call(add_1000_fn, {var_out});
236  builder.add_destruct({var_count, var_index});
237  builder.add_return();
238  builder.add_output_parameter(*var_out);
239 
240  EXPECT_TRUE(procedure.validate());
241 
242  MFProcedureExecutor procedure_fn{procedure};
243  MFParamsBuilder params{procedure_fn, 5};
244 
245  Array<int> counts = {4, 3, 7, 6, 4};
246  Array<int> results(5, -1);
247 
248  params.add_readonly_single_input(counts.as_span());
249  params.add_uninitialized_single_output(results.as_mutable_span());
250 
252  procedure_fn.call({0, 1, 3, 4}, params, context);
253 
254  EXPECT_EQ(results[0], 1016);
255  EXPECT_EQ(results[1], 1008);
256  EXPECT_EQ(results[2], -1);
257  EXPECT_EQ(results[3], 1064);
258  EXPECT_EQ(results[4], 1016);
259 }
260 
261 TEST(multi_function_procedure, Vectors)
262 {
274  CreateRangeFunction create_range_fn;
275  ConcatVectorsFunction extend_fn;
276  GenericAppendFunction append_fn{CPPType::get<int>()};
277  SumVectorFunction sum_elements_fn;
278  CustomMF_Constant<int> constant_5_fn{5};
279 
280  MFProcedure procedure;
281  MFProcedureBuilder builder{procedure};
282 
283  MFVariable *var_v1 = &builder.add_input_parameter(MFDataType::ForVector<int>());
284  MFVariable *var_v2 = &builder.add_parameter(MFParamType::ForMutableVector(CPPType::get<int>()));
285  builder.add_call(extend_fn, {var_v1, var_v2});
286  auto [var_constant] = builder.add_call<1>(constant_5_fn);
287  builder.add_call(append_fn, {var_v2, var_constant});
288  builder.add_destruct(*var_constant);
289  builder.add_call(extend_fn, {var_v2, var_v1});
290  auto [var_len] = builder.add_call<1>(sum_elements_fn, {var_v2});
291  auto [var_v3] = builder.add_call<1>(create_range_fn, {var_len});
292  builder.add_destruct({var_v1, var_len});
293  builder.add_return();
294  builder.add_output_parameter(*var_v3);
295 
296  EXPECT_TRUE(procedure.validate());
297 
298  MFProcedureExecutor procedure_fn{procedure};
299  MFParamsBuilder params{procedure_fn, 5};
300 
301  Array<int> v1 = {5, 2, 3};
302  GVectorArray v2{CPPType::get<int>(), 5};
303  GVectorArray v3{CPPType::get<int>(), 5};
304 
305  int value_10 = 10;
306  v2.append(0, &value_10);
307  v2.append(4, &value_10);
308 
309  params.add_readonly_vector_input(v1.as_span());
310  params.add_vector_mutable(v2);
311  params.add_vector_output(v3);
312 
314  procedure_fn.call({0, 1, 3, 4}, params, context);
315 
316  EXPECT_EQ(v2[0].size(), 6);
317  EXPECT_EQ(v2[1].size(), 4);
318  EXPECT_EQ(v2[2].size(), 0);
319  EXPECT_EQ(v2[3].size(), 4);
320  EXPECT_EQ(v2[4].size(), 6);
321 
322  EXPECT_EQ(v3[0].size(), 35);
323  EXPECT_EQ(v3[1].size(), 15);
324  EXPECT_EQ(v3[2].size(), 0);
325  EXPECT_EQ(v3[3].size(), 15);
326  EXPECT_EQ(v3[4].size(), 35);
327 }
328 
329 TEST(multi_function_procedure, BufferReuse)
330 {
341  CustomMF_SI_SO<int, int> add_10_fn{"add 10", [](int a) { return a + 10; }};
342 
343  MFProcedure procedure;
344  MFProcedureBuilder builder{procedure};
345 
346  MFVariable *var_a = &builder.add_single_input_parameter<int>();
347  auto [var_b] = builder.add_call<1>(add_10_fn, {var_a});
348  builder.add_destruct(*var_a);
349  auto [var_c] = builder.add_call<1>(add_10_fn, {var_b});
350  builder.add_destruct(*var_b);
351  auto [var_d] = builder.add_call<1>(add_10_fn, {var_c});
352  builder.add_destruct(*var_c);
353  auto [var_e] = builder.add_call<1>(add_10_fn, {var_d});
354  builder.add_destruct(*var_d);
355  auto [var_out] = builder.add_call<1>(add_10_fn, {var_e});
356  builder.add_destruct(*var_e);
357  builder.add_return();
358  builder.add_output_parameter(*var_out);
359 
360  EXPECT_TRUE(procedure.validate());
361 
362  MFProcedureExecutor procedure_fn{procedure};
363 
364  Array<int> inputs = {4, 1, 6, 2, 3};
365  Array<int> results(5, -1);
366 
367  MFParamsBuilder params{procedure_fn, 5};
368  params.add_readonly_single_input(inputs.as_span());
369  params.add_uninitialized_single_output(results.as_mutable_span());
370 
372  procedure_fn.call({0, 2, 3, 4}, params, context);
373 
374  EXPECT_EQ(results[0], 54);
375  EXPECT_EQ(results[1], -1);
376  EXPECT_EQ(results[2], 56);
377  EXPECT_EQ(results[3], 52);
378  EXPECT_EQ(results[4], 53);
379 }
380 
381 TEST(multi_function_procedure, OutputBufferReplaced)
382 {
383  MFProcedure procedure;
384  MFProcedureBuilder builder{procedure};
385 
386  const int output_value = 42;
387  CustomMF_GenericConstant constant_fn(CPPType::get<int>(), &output_value, false);
388  MFVariable &var_o = procedure.new_variable(MFDataType::ForSingle<int>());
389  builder.add_output_parameter(var_o);
390  builder.add_call_with_all_variables(constant_fn, {&var_o});
391  builder.add_destruct(var_o);
392  builder.add_call_with_all_variables(constant_fn, {&var_o});
393  builder.add_return();
394 
395  EXPECT_TRUE(procedure.validate());
396 
397  MFProcedureExecutor procedure_fn{procedure};
398 
399  Array<int> output(3, 0);
400  fn::MFParamsBuilder params(procedure_fn, output.size());
401  params.add_uninitialized_single_output(output.as_mutable_span());
402 
404  procedure_fn.call(IndexMask(output.size()), params, context);
405 
406  EXPECT_EQ(output[0], output_value);
407  EXPECT_EQ(output[1], output_value);
408  EXPECT_EQ(output[2], output_value);
409 }
410 
411 } // namespace blender::fn::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
Span< T > as_span() const
Definition: BLI_array.hh:231
MutableSpan< T > as_mutable_span()
Definition: BLI_array.hh:236
static MFParamType ForMutableVector(const CPPType &base_type)
Vector< MFVariable * > add_call(const MultiFunction &fn, Span< MFVariable * > input_and_mutable_variables={})
MFVariable & new_variable(MFDataType data_type, std::string name="")
void set_name(std::string name)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_global KernelShaderEvalInput ccl_global float * output
static unsigned a[3]
Definition: RandGen.cpp:78
TEST(field, ConstantFunction)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static bNodeSocketTemplate inputs[]