[Bf-blender-cvs] [94b98d3f882] temp-geometry-nodes-fields: fix bug when the same field is evaluated twice

Jacques Lucke noreply at git.blender.org
Fri Sep 3 13:29:31 CEST 2021


Commit: 94b98d3f882517076b652fd16734c673fb03a3a4
Author: Jacques Lucke
Date:   Fri Sep 3 12:54:28 2021 +0200
Branches: temp-geometry-nodes-fields
https://developer.blender.org/rB94b98d3f882517076b652fd16734c673fb03a3a4

fix bug when the same field is evaluated twice

===================================================================

M	source/blender/functions/FN_multi_function_builder.hh
M	source/blender/functions/intern/field.cc
M	source/blender/functions/intern/multi_function_builder.cc
M	source/blender/functions/tests/FN_field_test.cc

===================================================================

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



More information about the Bf-blender-cvs mailing list