[Bf-blender-cvs] [70eaba3cb1d] temp-geometry-nodes-fields--fields: Basic constant input test passes

Hans Goudey noreply at git.blender.org
Wed Aug 25 23:23:54 CEST 2021


Commit: 70eaba3cb1d74d5fb9ae12a7997ba1e8c5622a9a
Author: Hans Goudey
Date:   Wed Aug 25 16:23:46 2021 -0500
Branches: temp-geometry-nodes-fields--fields
https://developer.blender.org/rB70eaba3cb1d74d5fb9ae12a7997ba1e8c5622a9a

Basic constant input test passes

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

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

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

diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index a4ba9a61a85..5941034de78 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC_SYS
 
 set(SRC
   intern/cpp_types.cc
+  intern/field.cc
   intern/generic_vector_array.cc
   intern/generic_virtual_array.cc
   intern/generic_virtual_vector_array.cc
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 208f3ce2d76..daff025d0d6 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -24,7 +24,6 @@
 #include "BLI_map.hh"
 #include "BLI_vector.hh"
 
-#include "FN_generic_array.hh"
 #include "FN_generic_virtual_array.hh"
 #include "FN_multi_function_procedure.hh"
 #include "FN_multi_function_procedure_builder.hh"
@@ -33,152 +32,103 @@
 namespace blender::fn {
 
 class Field;
+using FieldPtr = std::unique_ptr<Field>;
 
 class Field {
-  fn::CPPType *type_;
+  const fn::CPPType *type_;
+  std::string debug_name_ = "";
 
  public:
-  fn::CPPType &type()
+  virtual ~Field() = default;
+  Field(const fn::CPPType &type, std::string &&debug_name = "")
+      : type_(&type), debug_name_(std::move(debug_name))
   {
+  }
+
+  const fn::CPPType &type() const
+  {
+    BLI_assert(type_ != nullptr);
     return *type_;
   }
 
-  virtual void foreach_input_recursive(blender::FunctionRef<void(const InputField &input)> fn) = 0;
-  virtual void foreach_input(blender::FunctionRef<void(const InputField &input)> fn) = 0;
+  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;
 };
 
+/**
+ * A field that doesn't have any dependencies on other fields.
+ *
+ * TODO: It might be an elegant simplification if every single field was a multi-function 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:
-  virtual GVArrayPtr get_data(IndexMask mask) const = 0;
-  void foreach_input_recursive(blender::FunctionRef<void(const InputField &input)> fn) final
+  InputField(const CPPType &type) : Field(type)
   {
   }
-  void foreach_input(blender::FunctionRef<void(const InputField &input)> fn) final
+
+  void foreach_input(blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final
   {
   }
-};
-
-class MultiFunctionField final : public Field {
-  blender::Vector<std::shared_ptr<Field>> input_fields_;
-  MultiFunction &function_;
-
- public:
-  void foreach_input_recursive(blender::FunctionRef<void(const InputField &input)> fn) final
+  void foreach_input_recursive(
+      blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final
   {
-    for (const std::shared_ptr<Field> &field : input_fields_) {
-      if (const InputField *input_field = dynamic_cast<const InputField *>(field.get())) {
-        fn(*input_field);
-      }
-      else {
-        field->foreach_input(fn);
-      }
-    }
   }
 
-  void foreach_input(blender::FunctionRef<void(const InputField &input)> fn) 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))
   {
-    for (const std::shared_ptr<Field> &field : input_fields_) {
-      if (const InputField *input_field = dynamic_cast<const InputField *>(field.get())) {
-        fn(*input_field);
-      }
-    }
+    return false;
   }
 };
 
-void add_procedure_inputs_recursive(const Field &field, MFProcedureBuilder &builder)
-{
-  field.foreach_input()
-}
-
 /**
- * Evaluate more than one prodecure at a time
+ * A field that takes inputs
  */
-void evaluate_fields(const Span<std::shared_ptr<Field>> fields,
-                     const MutableSpan<GMutableSpan> outputs,
-                     const IndexMask mask)
-{
-  blender::Map<const InputField *, GVArrayPtr> computed_inputs;
-  for (const std::shared_ptr<Field> &field : fields) {
-    field->foreach_input_recursive([&](const InputField &input_field) {
-      if (!computed_inputs.contains(&input_field)) {
-        computed_inputs.add_new(&input_field, input_field.get_data(mask));
-      }
-    });
-  }
-
-  /* Build procedure. */
-  MFProcedure procedure;
-  MFProcedureBuilder builder{procedure};
-
-  Map<const Field *, MFVariable *> fields_to_variables;
-  Map<const GMutableSpan, MFVariable *> outputs_to_variables;
-
-  /* Add the unique inputs. */
-  for (blender::Map<const InputField *, GVArrayPtr>::Item item : computed_inputs.items()) {
-    fields_to_variables.add_new(
-        item.key, &builder.add_parameter(MFParamType::ForSingleInput(item.value->type())));
-  }
+class MultiFunctionField final : public Field {
+  blender::Vector<FieldPtr> input_fields_;
+  const MultiFunction *function_;
 
-  /* Add the inputs recursively for the entire group of nodes. */
-  builder.add_return();
-  for (const int i : outputs.index_range()) {
-    BLI_assert(fields_to_variables.contains(fields[i].get()));
-    builder.add_output_parameter(*fields_to_variables.lookup(fields[i].get()));
+ public:
+  void foreach_input(blender::FunctionRef<void(const Field &input)> fn) const final
+  {
+    for (const FieldPtr &field : input_fields_) {
+      fn(*field);
+    }
   }
-  // builder.add_output_parameter(*var4);
-
-  BLI_assert(procedure.validate());
-
-  /* Evaluate procedure. */
-  MFProcedureExecutor executor{"Evaluate Field", procedure};
-  MFParamsBuilder params{executor, mask.min_array_size()};
-  MFContextBuilder context;
-
-  /* Add the input data. */
-  for (blender::Map<const InputField *, GVArrayPtr>::Item item : computed_inputs.items()) {
-    params.add_readonly_single_input(*item.value);
+  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);
+    }
   }
 
-  /* Add the output arrays. */
-  for (const int i : fields.index_range()) {
-    BLI_assert(outputs[i].type() == fields[i]->type());
-    params.add_uninitialized_single_output(outputs[i]);
+  const MultiFunction &function() const
+  {
+    BLI_assert(function_ != nullptr);
+    return *function_;
   }
+};
 
-  executor.call(mask, params, context);
-
-  // int input_index = 0;
-  // for (const int param_index : fn_->param_indices()) {
-  //   fn::MFParamType param_type = fn_->param_type(param_index);
-  //   switch (param_type.category()) {
-  //     case fn::MFParamType::SingleInput: {
-  //       const Field &field = *input_fields_[input_index];
-  //       FieldOutput &output = scope.add_value(field.evaluate(mask, inputs), __func__);
-  //       params.add_readonly_single_input(output.varray_ref());
-  //       input_index++;
-  //       break;
-  //     }
-  //     case fn::MFParamType::SingleOutput: {
-  //       const CPPType &type = param_type.data_type().single_type();
-  //       void *buffer = MEM_mallocN_aligned(
-  //           mask.min_array_size() * type.size(), type.alignment(), __func__);
-  //       GMutableSpan span{type, buffer, mask.min_array_size()};
-  //       outputs.append(span);
-  //       params.add_uninitialized_single_output(span);
-  //       if (param_index == output_param_index_) {
-  //         output_span_index = outputs.size() - 1;
-  //       }
-  //       break;
-  //     }
-  //     case fn::MFParamType::SingleMutable:
-  //     case fn::MFParamType::VectorInput:
-  //     case fn::MFParamType::VectorMutable:
-  //     case fn::MFParamType::VectorOutput:
-  //       BLI_assert_unreachable();
-  //       break;
-  //   }
-  // }
-}
+/**
+ * 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,
+                     const blender::MutableSpan<GMutableSpan> outputs,
+                     const blender::IndexMask mask);
 
 }  // namespace blender::fn
\ No newline at end of file
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
new file mode 100644
index 00000000000..e2c25ac1ad7
--- /dev/null
+++ b/source/blender/functions/intern/field.cc
@@ -0,0 +1,134 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_field.hh"
+
+namespace blender::fn {
+
+static void add_field_parameters(const Field &field,
+                                 MFProcedureBuilder &builder,
+                                 Map<const Field *, MFVariable *> &variable_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);
+    });
+
+    /* 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)); });

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list