Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-09-03 13:54:28 +0300
committerJacques Lucke <jacques@blender.org>2021-09-03 13:54:28 +0300
commit94b98d3f882517076b652fd16734c673fb03a3a4 (patch)
tree213ff27d6e54ad27118d941904f074f0f106593d /source/blender/functions
parent32f101c6038b83256fc505b5f06018296f4fe446 (diff)
fix bug when the same field is evaluated twice
Diffstat (limited to 'source/blender/functions')
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh9
-rw-r--r--source/blender/functions/intern/field.cc15
-rw-r--r--source/blender/functions/intern/multi_function_builder.cc28
-rw-r--r--source/blender/functions/tests/FN_field_test.cc20
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 &copy_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