[Bf-blender-cvs] [81a0c384dae] temp-geometry-nodes-fields--fields: Experimental simplification: non-virtual multi-function-only fields

Hans Goudey noreply at git.blender.org
Thu Aug 26 00:39:27 CEST 2021


Commit: 81a0c384daefdb370c83b257078f59c7dfda7711
Author: Hans Goudey
Date:   Wed Aug 25 17:39:19 2021 -0500
Branches: temp-geometry-nodes-fields--fields
https://developer.blender.org/rB81a0c384daefdb370c83b257078f59c7dfda7711

Experimental simplification: non-virtual multi-function-only fields

The stupidly simple test doesn't pass anymore.

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

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 daff025d0d6..9ccdca4238c 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -32,16 +32,20 @@
 namespace blender::fn {
 
 class Field;
-using FieldPtr = std::unique_ptr<Field>;
 
 class Field {
   const fn::CPPType *type_;
+  // std::unique_ptr<MultiFunction> function_;
+  const MultiFunction *function_;
+
+  blender::Vector<std::shared_ptr<Field>> input_fields_;
+
   std::string debug_name_ = "";
 
  public:
-  virtual ~Field() = default;
-  Field(const fn::CPPType &type, std::string &&debug_name = "")
-      : type_(&type), debug_name_(std::move(debug_name))
+  ~Field() = default;
+  Field(const fn::CPPType &type, const MultiFunction &function)
+      : type_(&type), function_(&function)
   {
   }
 
@@ -51,14 +55,30 @@ class Field {
     return *type_;
   }
 
+  const MultiFunction &function() const
+  {
+    BLI_assert(function_ != nullptr);
+    return *function_;
+  }
+
   blender::StringRef debug_name() const
   {
     return debug_name_;
   }
 
-  virtual void foreach_input(blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const = 0;
-  virtual void foreach_input_recursive(
-      blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const = 0;
+  void foreach_input(blender::FunctionRef<void(const Field &input)> fn) const
+  {
+    for (const std::shared_ptr<Field> &field : input_fields_) {
+      fn(*field);
+    }
+  }
+  void foreach_input_recursive(blender::FunctionRef<void(const Field &input)> fn) const
+  {
+    for (const std::shared_ptr<Field> &field : input_fields_) {
+      fn(*field);
+      field->foreach_input(fn);
+    }
+  }
 };
 
 /**
@@ -68,66 +88,66 @@ class Field {
  * and input fields just happened to have no inputs. Then it might not need to be a virtual class,
  * since the dynamic behavior would be contained in the multifunction, which would be very nice.
  */
-class InputField : public Field {
- public:
-  InputField(const CPPType &type) : Field(type)
-  {
-  }
-
-  void foreach_input(blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final
-  {
-  }
-  void foreach_input_recursive(
-      blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final
-  {
-  }
-
-  virtual GVArrayPtr get_data(IndexMask mask) const = 0;
-
-  /**
-   * Return true when the field input is the same as another field, used as an
-   * optimization to avoid creating multiple virtual arrays for the same input node.
-   */
-  virtual bool equals(const InputField &UNUSED(other))
-  {
-    return false;
-  }
-};
+// class InputField : public Field {
+//  public:
+//   InputField(const CPPType &type) : Field(type)
+//   {
+//   }
+
+//   void foreach_input(blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final
+//   {
+//   }
+//   void foreach_input_recursive(
+//       blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final
+//   {
+//   }
+
+//   virtual GVArrayPtr get_data(IndexMask mask) const = 0;
+
+//   /**
+//    * Return true when the field input is the same as another field, used as an
+//    * optimization to avoid creating multiple virtual arrays for the same input node.
+//    */
+//   virtual bool equals(const InputField &UNUSED(other))
+//   {
+//     return false;
+//   }
+// };
 
 /**
  * A field that takes inputs
  */
-class MultiFunctionField final : public Field {
-  blender::Vector<FieldPtr> input_fields_;
-  const MultiFunction *function_;
-
- public:
-  void foreach_input(blender::FunctionRef<void(const Field &input)> fn) const final
-  {
-    for (const FieldPtr &field : input_fields_) {
-      fn(*field);
-    }
-  }
-  void foreach_input_recursive(blender::FunctionRef<void(const Field &input)> fn) const final
-  {
-    for (const FieldPtr &field : input_fields_) {
-      fn(*field);
-      field->foreach_input(fn);
-    }
-  }
-
-  const MultiFunction &function() const
-  {
-    BLI_assert(function_ != nullptr);
-    return *function_;
-  }
-};
+// class MultiFunctionField final : public Field {
+//   blender::Vector<FieldPtr> input_fields_;
+//   const MultiFunction *function_;
+
+//  public:
+//   void foreach_input(blender::FunctionRef<void(const Field &input)> fn) const final
+//   {
+//     for (const FieldPtr &field : input_fields_) {
+//       fn(*field);
+//     }
+//   }
+//   void foreach_input_recursive(blender::FunctionRef<void(const Field &input)> fn) const final
+//   {
+//     for (const FieldPtr &field : input_fields_) {
+//       fn(*field);
+//       field->foreach_input(fn);
+//     }
+//   }
+
+//   const MultiFunction &function() const
+//   {
+//     BLI_assert(function_ != nullptr);
+//     return *function_;
+//   }
+// };
 
 /**
  * Evaluate more than one field at a time, as an optimization
  * in case they share inputs or various intermediate values.
  */
-void evaluate_fields(const blender::Span<FieldPtr> fields,
+void evaluate_fields(const blender::Span<Field> fields,
                      const blender::MutableSpan<GMutableSpan> outputs,
                      const blender::IndexMask mask);
 
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index e2c25ac1ad7..acecbfd79ec 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -20,64 +20,51 @@ namespace blender::fn {
 
 static void add_field_parameters(const Field &field,
                                  MFProcedureBuilder &builder,
-                                 Map<const Field *, MFVariable *> &variable_map)
+                                 Map<const Field *, MFVariable *> &output_map)
 {
-  if (const MultiFunctionField *mf_field = dynamic_cast<const MultiFunctionField *>(&field)) {
-    /* Recursively make sure all of the inputs have entries in the parameter map. */
-    mf_field->foreach_input_recursive([&](const Field &input_field) {
-      add_field_parameters(input_field, builder, variable_map);
-    });
+  /* Recursively make sure all of the inputs have entries in the variable map. */
+  field.foreach_input_recursive(
+      [&](const Field &input_field) { add_field_parameters(input_field, builder, output_map); });
 
-    /* Gather the immediate inputs to this field. */
-    Vector<MFVariable *> inputs;
-    mf_field->foreach_input(
-        [&](const Field &input_field) { inputs.append(variable_map.lookup(&input_field)); });
+  /* Add the immediate inputs to this field. */
+  field.foreach_input([&](const Field &input_field) {
+    builder.add_input_parameter(output_map.lookup(&input_field)->data_type());
+  });
 
-    for (const int i : inputs.index_range()) {
-      builder.add_input_parameter(inputs[i]->data_type());
-    }
+  Vector<MFVariable *> outputs = builder.add_call(field.function());
 
-    Vector<MFVariable *> outputs = builder.add_call(mf_field->function());
+  // builder.add_destruct(inputs);
 
-    // builder.add_destruct(inputs);
-
-    /* TODO: How to support multiple outputs?! */
-    BLI_assert(outputs.size() == 1);
-    variable_map.add_new(mf_field, outputs.first());
-  }
-  else if (const InputField *input_field = dynamic_cast<const InputField *>(&field)) {
-    variable_map.add_new(input_field,
-                         &builder.add_input_parameter(MFDataType::ForSingle(field.type()),
-                                                      std::string(field.debug_name())));
-  }
+  /* TODO: How to support multiple outputs?! */
+  BLI_assert(outputs.size() == 1);
+  output_map.add_new(&field, outputs.first());
 }
 
-static void build_procedure(const Span<FieldPtr> fields, MFProcedure &procedure)
+static void build_procedure(const Span<Field> fields, MFProcedure &procedure)
 {
   MFProcedureBuilder builder{procedure};
 
-  Map<const Field *, MFVariable *> variable_map;
-
-  for (const FieldPtr &field : fields) {
-    if (dynamic_cast<const InputField *>(field.get())) {
-      continue;
-    }
+  Map<const Field *, MFVariable *> output_map;
 
-    add_field_parameters(*field, builder, variable_map);
+  for (const Field &field : fields) {
+    add_field_parameters(field, builder, output_map);
   }
 
   /* TODO: Move this to the proper place. */
-  for (MFVariable *variable : variable_map.values()) {
+  for (MFVariable *variable : output_map.values()) {
     builder.add_destruct(*variable);
   }
 
   builder.add_return();
 
+  for (const Field &field : fields) {
+    builder.add_output_parameter(*output_map.lookup(&field));
+  }
+
   BLI_assert(procedure.validate());
 }
 
 static void evaluate_procedure(MFProcedure &procedure,
-                               const Span<FieldPtr> fields,
                                const IndexMask mask,
                                const MutableSpan<GMutableSpan> outputs)
 {
@@ -85,34 +72,9 @@ static void evaluate_procedure(MFProcedure &procedure,
   MFParamsBuilder params{executor, mask.min_array_size()};
   MFContextBuilder context;
 
-  /* Add the input data from the input fields. */
-  Map<const InputField *, GVArrayPtr> computed_inputs;
-  for (const FieldPtr &field : fields) {
-    if (const InputField *input_field = dynamic_cast<const InputField *>(field.get())) {
-      if (!computed_inputs.contains(input_field)) {
-        computed_inputs.add_new(input_field, input_field->get_data(mask));
-      }
-      continue;
-    }
-    field->foreach_input_recursive([&](const Field &field) {
-      if (const InputField *input_field = dynamic_cast<const InputField *>(&field)) {
-        /* TODO: Optimize, too many lookups. */
-        if (!computed_inputs.contains(input_field)) {
-          computed_inputs.add_new(input_field, input_field->get_data(mask));
-        }
-        params.add_readonly_single_input(*computed_inputs.lookup(input_field));
-      }
-    });
-  }
-
   /* Add the output arrays. */
   for (const int i : outputs.index_range()) {
-    if (const InputField *input_field = dynamic_cast<const InputField *>(fields[i].get())) {
-      computed_inputs.lookup(input_field)->materialize(mask, outputs[i].data());
-    }
-    else {
-      params.add_uninitialized_single_output(outputs[i]);
-    }
+    params.add_uninitialized_single_output(outputs[i]);
   }
 
   ex

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list