[Bf-blender-cvs] [7cb4665beeb] temp-geometry-nodes-fields: new FieldEvaluator utility class

Jacques Lucke noreply at git.blender.org
Wed Sep 1 18:01:56 CEST 2021


Commit: 7cb4665beeb72b83999950dad3978a3be8994795
Author: Jacques Lucke
Date:   Wed Sep 1 18:01:48 2021 +0200
Branches: temp-geometry-nodes-fields
https://developer.blender.org/rB7cb4665beeb72b83999950dad3978a3be8994795

new FieldEvaluator utility class

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

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

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

diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 0cf83e25d0b..76ffb0225ab 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -128,6 +128,11 @@ template<typename T> class Field : public GField {
   {
     BLI_assert(this->cpp_type().template is<T>());
   }
+
+  Field(std::shared_ptr<FieldSource> source, const int source_output_index = 0)
+      : Field(GField(std::move(source), source_output_index))
+  {
+  }
 };
 
 class OperationFieldSource : public FieldSource {
@@ -225,14 +230,14 @@ class ContextFieldSource : public FieldSource {
 Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
                                         Span<const GField *> fields_to_evaluate,
                                         IndexMask mask,
-                                        FieldContext &context,
+                                        const FieldContext &context,
                                         Span<GVMutableArray *> dst_hints = {});
 
 void evaluate_constant_field(const GField &field, void *r_value);
 
 void evaluate_fields_to_spans(Span<const GField *> fields_to_evaluate,
                               IndexMask mask,
-                              FieldContext &context,
+                              const FieldContext &context,
                               Span<GMutableSpan> out_spans);
 
 template<typename T> T evaluate_constant_field(const Field<T> &field)
@@ -250,4 +255,107 @@ template<typename T> Field<T> make_constant_field(T value)
   return Field<T>{GField{std::move(operation), 0}};
 }
 
+class FieldEvaluator;
+
+class GFieldOutputHandle {
+ protected:
+  FieldEvaluator *evaluator_;
+  int field_index_;
+
+ public:
+  GFieldOutputHandle(FieldEvaluator &evaluator, int field_index)
+      : evaluator_(&evaluator), field_index_(field_index)
+  {
+  }
+
+  const GVArray &get();
+};
+
+template<typename T> class FieldOutputHandle : GFieldOutputHandle {
+ public:
+  explicit FieldOutputHandle(const GFieldOutputHandle &other) : GFieldOutputHandle(other)
+  {
+  }
+
+  const VArray<T> &get();
+};
+
+class FieldEvaluator : NonMovable, NonCopyable {
+ private:
+  ResourceScope scope_;
+  const FieldContext &context_;
+  const IndexMask mask_;
+  Vector<GField> fields_to_evaluate_;
+  Vector<GVMutableArray *> dst_hints_;
+  Vector<const GVArray *> evaluated_varrays_;
+  bool is_evaluated_ = false;
+
+ public:
+  /** Takes #mask by pointer because the mask has to live longer than the evaluator. */
+  FieldEvaluator(const FieldContext &context, const IndexMask *mask)
+      : context_(context), mask_(*mask)
+  {
+  }
+
+  GFieldOutputHandle add(GField field, GVMutableArray *dst_hint = nullptr)
+  {
+    const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
+    dst_hints_.append(dst_hint);
+    return GFieldOutputHandle(*this, field_index);
+  }
+
+  template<typename T>
+  FieldOutputHandle<T> add(Field<T> field, VMutableArray<T> *dst_hint = nullptr)
+  {
+    GVMutableArray *generic_dst_hint = nullptr;
+    if (dst_hint != nullptr) {
+      generic_dst_hint = &scope_.construct<GVMutableArray_For_VMutableArray<T>>(__func__,
+                                                                                *dst_hint);
+    }
+    return FieldOutputHandle<T>(this->add(GField(std::move(field)), generic_dst_hint));
+  }
+
+  void evaluate()
+  {
+    BLI_assert_msg(!is_evaluated_, "Cannot evaluate twice.");
+    Array<const GField *> fields(fields_to_evaluate_.size());
+    for (const int i : fields_to_evaluate_.index_range()) {
+      fields[i] = &fields_to_evaluate_[i];
+    }
+    evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_hints_);
+    is_evaluated_ = true;
+  }
+
+  const GVArray &get(const int field_index) const
+  {
+    BLI_assert(is_evaluated_);
+    return *evaluated_varrays_[field_index];
+  }
+
+  template<typename T> const VArray<T> &get(const int field_index)
+  {
+    const GVArray &varray = this->get(field_index);
+    GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(__func__, varray);
+    return *typed_varray;
+  }
+};
+
+/* --------------------------------------------------------------------
+ * GFieldOutputHandle inline methods.
+ */
+
+inline const GVArray &GFieldOutputHandle::get()
+{
+  return evaluator_->get(field_index_);
+}
+
+/* --------------------------------------------------------------------
+ * FieldOutputHandle inline methods.
+ */
+
+template<typename T> inline const VArray<T> &FieldOutputHandle<T>::get()
+{
+  return evaluator_->get<T>(field_index_);
+}
+
 }  // namespace blender::fn
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 24d6ab0477f..24a5bc907a8 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -88,7 +88,7 @@ static FieldGraphInfo preprocess_field_graph(Span<const GField *> entry_fields)
 
 static Vector<const GVArray *> get_field_context_inputs(ResourceScope &scope,
                                                         const IndexMask mask,
-                                                        FieldContext &context,
+                                                        const FieldContext &context,
                                                         const FieldGraphInfo &graph_info)
 {
   Vector<const GVArray *> field_context_inputs;
@@ -238,7 +238,7 @@ struct PartiallyInitializedArray : NonCopyable, NonMovable {
 Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
                                         Span<const GField *> fields_to_evaluate,
                                         IndexMask mask,
-                                        FieldContext &context,
+                                        const FieldContext &context,
                                         Span<GVMutableArray *> dst_hints)
 {
   Vector<const GVArray *> r_varrays(fields_to_evaluate.size(), nullptr);
@@ -408,7 +408,7 @@ void evaluate_constant_field(const GField &field, void *r_value)
 
 void evaluate_fields_to_spans(Span<const GField *> fields_to_evaluate,
                               IndexMask mask,
-                              FieldContext &context,
+                              const FieldContext &context,
                               Span<GMutableSpan> out_spans)
 {
   ResourceScope scope;
diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc
index 67708331c6d..0eb9e9e1351 100644
--- a/source/blender/functions/tests/FN_field_test.cc
+++ b/source/blender/functions/tests/FN_field_test.cc
@@ -207,24 +207,26 @@ TEST(field, TwoFunctionsTwoOutputs)
       OperationFieldSource(std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"),
                            {index_field, index_field}));
 
-  GField result_field_1{fn, 0};
-  GField intermediate_field{fn, 1};
+  Vector<int64_t> mask_indices = {2, 4, 6, 8};
+  IndexMask mask = mask_indices.as_span();
+
+  Field<int> result_field_1{fn, 0};
+  Field<int> intermediate_field{fn, 1};
 
   std::unique_ptr<MultiFunction> add_10_fn = std::make_unique<CustomMF_SI_SO<int, int>>(
       "add_10", [](int a) { return a + 10; });
-  GField result_field_2{std::make_shared<OperationFieldSource>(
-                            OperationFieldSource(std::move(add_10_fn), {intermediate_field})),
-                        0};
+  Field<int> result_field_2{std::make_shared<OperationFieldSource>(
+                                OperationFieldSource(std::move(add_10_fn), {intermediate_field})),
+                            0};
 
-  Array<int> result_1(10);
-  Array<int> result_2(10);
-  GMutableSpan result_generic_1(result_1.as_mutable_span());
-  GMutableSpan result_generic_2(result_2.as_mutable_span());
   FieldContext field_context;
-  evaluate_fields_to_spans({&result_field_1, &result_field_2},
-                           {2, 4, 6, 8},
-                           field_context,
-                           {result_generic_1, result_generic_2});
+  FieldEvaluator field_evaluator{field_context, &mask};
+  FieldOutputHandle<int> handle_1 = field_evaluator.add(result_field_1);
+  FieldOutputHandle<int> handle_2 = field_evaluator.add(result_field_2);
+  field_evaluator.evaluate();
+  const VArray<int> &result_1 = handle_1.get();
+  const VArray<int> &result_2 = handle_2.get();
+
   EXPECT_EQ(result_1[2], 4);
   EXPECT_EQ(result_1[4], 8);
   EXPECT_EQ(result_1[6], 12);



More information about the Bf-blender-cvs mailing list