diff options
Diffstat (limited to 'source/blender/functions')
-rw-r--r-- | source/blender/functions/FN_multi_function_builder.hh | 9 | ||||
-rw-r--r-- | source/blender/functions/intern/field.cc | 15 | ||||
-rw-r--r-- | source/blender/functions/intern/multi_function_builder.cc | 28 | ||||
-rw-r--r-- | source/blender/functions/tests/FN_field_test.cc | 20 |
4 files changed, 69 insertions, 3 deletions
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 7a526bb640b..d13615ced07 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -417,4 +417,13 @@ class CustomMF_DefaultOutput : public MultiFunction { void call(IndexMask mask, MFParams params, MFContext context) const override; }; +class CustomMF_GenericCopy : public MultiFunction { + private: + MFSignature signature_; + + public: + CustomMF_GenericCopy(StringRef name, MFDataType data_type); + void call(IndexMask mask, MFParams params, MFContext context) const override; +}; + } // namespace blender::fn diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 6d8fce07f5a..073908e6c1d 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -136,6 +136,7 @@ static Set<const GField *> find_varying_fields(const FieldGraphInfo &graph_info, } static void build_multi_function_procedure_for_fields(MFProcedure &procedure, + ResourceScope &scope, const FieldGraphInfo &graph_info, Span<const GField *> output_fields) { @@ -187,9 +188,15 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, } } - /* TODO: Handle case when there are duplicates in #output_fields. */ + Set<MFVariable *> already_output_variables; for (const GField *field : output_fields) { MFVariable *variable = variable_by_field.lookup(*field); + if (!already_output_variables.add(variable)) { + /* The same variable is output twice. Create a copy to make it work. */ + const MultiFunction ©_fn = scope.construct<CustomMF_GenericCopy>( + __func__, "copy", variable->data_type()); + variable = builder.add_call<1>(copy_fn, {variable})[0]; + } builder.add_output_parameter(*variable); } @@ -293,7 +300,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, const int array_size = mask.min_array_size(); if (!varying_fields_to_evaluate.is_empty()) { MFProcedure procedure; - build_multi_function_procedure_for_fields(procedure, graph_info, varying_fields_to_evaluate); + build_multi_function_procedure_for_fields( + procedure, scope, graph_info, varying_fields_to_evaluate); MFProcedureExecutor procedure_executor{"Procedure", procedure}; MFParamsBuilder mf_params{procedure_executor, mask.min_array_size()}; MFContextBuilder mf_context; @@ -335,7 +343,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, } if (!constant_fields_to_evaluate.is_empty()) { MFProcedure procedure; - build_multi_function_procedure_for_fields(procedure, graph_info, constant_fields_to_evaluate); + build_multi_function_procedure_for_fields( + procedure, scope, graph_info, constant_fields_to_evaluate); MFProcedureExecutor procedure_executor{"Procedure", procedure}; MFParamsBuilder mf_params{procedure_executor, 1}; MFContextBuilder mf_context; diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc index c6b3b808130..180d1f17a54 100644 --- a/source/blender/functions/intern/multi_function_builder.cc +++ b/source/blender/functions/intern/multi_function_builder.cc @@ -123,4 +123,32 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU } } +CustomMF_GenericCopy::CustomMF_GenericCopy(StringRef name, MFDataType data_type) +{ + MFSignatureBuilder signature{name}; + signature.input("Input", data_type); + signature.output("Output", data_type); + signature_ = signature.build(); + this->set_signature(&signature_); +} + +void CustomMF_GenericCopy::call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const +{ + const MFDataType data_type = this->param_type(0).data_type(); + switch (data_type.category()) { + case MFDataType::Single: { + const GVArray &inputs = params.readonly_single_input(0, "Input"); + GMutableSpan outputs = params.uninitialized_single_output(1, "Output"); + inputs.materialize_to_uninitialized(mask, outputs.data()); + break; + } + case MFDataType::Vector: { + const GVVectorArray &inputs = params.readonly_vector_input(0, "Input"); + GVectorArray &outputs = params.vector_output(1, "Output"); + outputs.extend(mask, inputs); + break; + } + } +} + } // namespace blender::fn diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc index 67fda512c92..b02e14559b5 100644 --- a/source/blender/functions/tests/FN_field_test.cc +++ b/source/blender/functions/tests/FN_field_test.cc @@ -237,4 +237,24 @@ TEST(field, TwoFunctionsTwoOutputs) EXPECT_EQ(result_2->get(8), 36); } +TEST(field, SameFieldTwice) +{ + GField constant_field{ + std::make_shared<OperationFieldSource>(std::make_unique<CustomMF_Constant<int>>(10)), 0}; + + FieldContext field_context; + IndexMask mask{IndexRange(2)}; + ResourceScope scope; + Vector<const GVArray *> results = evaluate_fields( + scope, {&constant_field, &constant_field}, mask, field_context); + + GVArray_Typed<int> varray1{*results[0]}; + GVArray_Typed<int> varray2{*results[1]}; + + EXPECT_EQ(varray1->get(0), 10); + EXPECT_EQ(varray1->get(1), 10); + EXPECT_EQ(varray2->get(0), 10); + EXPECT_EQ(varray2->get(1), 10); +} + } // namespace blender::fn::tests |