[Bf-blender-cvs] [d6bddbef2df] temp-geometry-nodes-fields: add more flexible field evaluation method

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


Commit: d6bddbef2dfa63ab9f1e1a5a00308f2607d8279b
Author: Jacques Lucke
Date:   Wed Sep 1 17:00:26 2021 +0200
Branches: temp-geometry-nodes-fields
https://developer.blender.org/rBd6bddbef2dfa63ab9f1e1a5a00308f2607d8279b

add more flexible field evaluation method

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

M	source/blender/blenlib/BLI_hash.hh
M	source/blender/functions/FN_field.hh
M	source/blender/functions/intern/field.cc
M	source/blender/functions/tests/FN_field_test.cc
M	source/blender/modifiers/intern/MOD_nodes_evaluator.cc
M	source/blender/nodes/NOD_geometry_exec.hh

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

diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh
index fbed321534c..11ff7d040aa 100644
--- a/source/blender/blenlib/BLI_hash.hh
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -250,6 +250,20 @@ template<typename T> struct DefaultHash<std::unique_ptr<T>> {
   }
 };
 
+template<typename T> struct DefaultHash<std::shared_ptr<T>> {
+  uint64_t operator()(const std::shared_ptr<T> &value) const
+  {
+    return get_default_hash(value.get());
+  }
+};
+
+template<typename T> struct DefaultHash<std::reference_wrapper<T>> {
+  uint64_t operator()(const std::reference_wrapper<T> &value) const
+  {
+    return get_default_hash(value.get());
+  }
+};
+
 template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> {
   uint64_t operator()(const std::pair<T1, T2> &value) const
   {
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 9217d98d75b..0cf83e25d0b 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -47,10 +47,30 @@ class FieldSource {
 
   virtual const CPPType &cpp_type_of_output_index(int output_index) const = 0;
 
-  virtual bool is_input() const
+  virtual bool is_context_source() const
   {
     return false;
   }
+
+  virtual bool is_operation_source() const
+  {
+    return false;
+  }
+
+  virtual uint64_t hash() const
+  {
+    return get_default_hash(this);
+  }
+
+  friend bool operator==(const FieldSource &a, const FieldSource &b)
+  {
+    return a.is_equal_to(b);
+  }
+
+  virtual bool is_equal_to(const FieldSource &other) const
+  {
+    return this == &other;
+  }
 };
 
 /**
@@ -79,9 +99,14 @@ class GField {
     return source_->cpp_type_of_output_index(source_output_index_);
   }
 
-  bool is_input() const
+  bool has_context_source() const
   {
-    return source_->is_input();
+    return source_->is_context_source();
+  }
+
+  bool has_operation_source() const
+  {
+    return source_->is_operation_source();
   }
 
   const FieldSource &source() const
@@ -105,20 +130,20 @@ template<typename T> class Field : public GField {
   }
 };
 
-class FieldOperation : public FieldSource {
+class OperationFieldSource : public FieldSource {
   std::unique_ptr<const MultiFunction> owned_function_;
   const MultiFunction *function_;
 
   blender::Vector<GField> inputs_;
 
  public:
-  FieldOperation(std::unique_ptr<const MultiFunction> function, Vector<GField> inputs = {})
+  OperationFieldSource(std::unique_ptr<const MultiFunction> function, Vector<GField> inputs = {})
       : owned_function_(std::move(function)), inputs_(std::move(inputs))
   {
     function_ = owned_function_.get();
   }
 
-  FieldOperation(const MultiFunction &function, Vector<GField> inputs = {})
+  OperationFieldSource(const MultiFunction &function, Vector<GField> inputs = {})
       : function_(&function), inputs_(std::move(inputs))
   {
   }
@@ -133,6 +158,11 @@ class FieldOperation : public FieldSource {
     return *function_;
   }
 
+  bool is_operation_source() const override
+  {
+    return true;
+  }
+
   const CPPType &cpp_type_of_output_index(int output_index) const override
   {
     int output_counter = 0;
@@ -150,18 +180,25 @@ class FieldOperation : public FieldSource {
   }
 };
 
-class FieldInput : public FieldSource {
+class FieldContext {
+ public:
+  ~FieldContext() = default;
+};
+
+class ContextFieldSource : public FieldSource {
  protected:
   const CPPType *type_;
   std::string debug_name_;
 
  public:
-  FieldInput(const CPPType &type, std::string debug_name = "")
+  ContextFieldSource(const CPPType &type, std::string debug_name = "")
       : type_(&type), debug_name_(std::move(debug_name))
   {
   }
 
-  virtual GVArrayPtr get_varray_generic_context(IndexMask mask) const = 0;
+  virtual const GVArray *try_get_varray_for_context(const FieldContext &context,
+                                                    IndexMask mask,
+                                                    ResourceScope &scope) const = 0;
 
   blender::StringRef debug_name() const
   {
@@ -179,21 +216,25 @@ class FieldInput : public FieldSource {
     return *type_;
   }
 
-  bool is_input() const override
+  bool is_context_source() const override
   {
     return true;
   }
 };
 
-/**
- * Evaluate more than one field at a time, as an optimization
- * in case they share inputs or various intermediate values.
- */
-void evaluate_fields(blender::Span<GField> fields,
-                     blender::IndexMask mask,
-                     blender::Span<GMutableSpan> outputs);
+Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
+                                        Span<const GField *> fields_to_evaluate,
+                                        IndexMask mask,
+                                        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,
+                              Span<GMutableSpan> out_spans);
+
 template<typename T> T evaluate_constant_field(const Field<T> &field)
 {
   T value;
@@ -205,7 +246,7 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
 template<typename T> Field<T> make_constant_field(T value)
 {
   auto constant_fn = std::make_unique<fn::CustomMF_Constant<T>>(std::forward<T>(value));
-  auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
+  auto operation = std::make_shared<OperationFieldSource>(std::move(constant_fn));
   return Field<T>{GField{std::move(operation), 0}};
 }
 
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 87cfc60d502..24d6ab0477f 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -15,273 +15,408 @@
  */
 
 #include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
 #include "BLI_set.hh"
 #include "BLI_stack.hh"
+#include "BLI_vector_set.hh"
 
 #include "FN_field.hh"
 
 namespace blender::fn {
 
-/**
- * A map to hold the output variables for each function output or input so they can be reused.
- */
-using VariableMap = Map<const FieldSource *, Vector<MFVariable *>>;
+struct GFieldRef {
+  const FieldSource *source;
+  int index;
 
-/**
- * A map of the computed inputs for all of a field system's inputs, to avoid creating duplicates.
- * Usually virtual arrays are just references, but sometimes they can be heavier as well.
- */
-using ComputedInputMap = Map<const MFVariable *, GVArrayPtr>;
+  GFieldRef(const FieldSource &source, const int index) : source(&source), index(index)
+  {
+  }
 
-static MFVariable &get_field_variable(const GField &field, VariableMap &unique_variables)
-{
-  if (field.is_input()) {
-    const FieldInput &input = dynamic_cast<const FieldInput &>(field.source());
-    return *unique_variables.lookup(&input).first();
+  GFieldRef(const GField &field) : source(&field.source()), index(field.source_output_index())
+  {
   }
-  const FieldOperation &operation = dynamic_cast<const FieldOperation &>(field.source());
-  MutableSpan<MFVariable *> operation_outputs = unique_variables.lookup(&operation);
-  return *operation_outputs[field.source_output_index()];
-}
 
-static const MFVariable &get_field_variable(const GField &field,
-                                            const VariableMap &unique_variables)
-{
-  if (field.is_input()) {
-    const FieldInput &input = dynamic_cast<const FieldInput &>(field.source());
-    return *unique_variables.lookup(&input).first();
+  uint64_t hash() const
+  {
+    return get_default_hash_2(*source, index);
   }
-  const FieldOperation &operation = dynamic_cast<const FieldOperation &>(field.source());
-  Span<MFVariable *> operation_outputs = unique_variables.lookup(&operation);
-  return *operation_outputs[field.source_output_index()];
-}
 
-/**
- * TODO: Merge duplicate input nodes, not just fields pointing to the same FieldInput.
- */
-static void add_variables_for_input(const GField &field,
-                                    Stack<const GField *> &fields_to_visit,
-                                    MFProcedureBuilder &builder,
-                                    VariableMap &unique_variables)
-{
-  fields_to_visit.pop();
-  const FieldInput &input = dynamic_cast<const FieldInput &>(field.source());
-  MFVariable &variable = builder.add_input_parameter(MFDataType::ForSingle(field.cpp_type()),
-                                                     input.debug_name());
-  unique_variables.add(&input, {&variable});
-}
+  friend bool operator==(const GFieldRef &a, const GFieldRef &b)
+  {
+    return *a.source == *b.source && a.index == b.index;
+  }
+};
+
+struct FieldGraphInfo {
+  MultiValueMap<GFieldRef, const GField *> field_users;
+  VectorSet<std::reference_wrapper<const ContextFieldSource>> deduplicated_context_sources;
+};
 
-static void add_variables_for_operation(const GField &field,
-                                        Stack<const GField *> &fields_to_visit,
-                                        MFProcedureBuilder &builder,
-                                        VariableMap &unique_variables)
+static FieldGraphInfo preprocess_field_graph(Span<const GField *> entry_fields)
 {
-  const FieldOperation &operation = dynamic_cast<const FieldOperation &>(field.source());
-  for (const GField &input_field : operation.inputs()) {
-    if (!unique_variables.contains(&input_field.source())) {
-      /* The field for this input hasn't been handled yet. Handle it now, so that we know all
-       * of this field's function inputs already have variables. TODO: Verify that this is the
-       * best way to do a depth first traversal. These extra lookups don't seem ideal. */
-      fields_to_visit.push(&input_field);
-      return;
-    }
-  }
+  FieldGraphInfo graph_info;
 
-  fields_to_visit.pop();
+  Stack<const GField *> fields_to_check;
+  Set<const GField *> handled_fields;
 
-  Vector<MFVariable *> inputs;
-  Set<MFVariable *> unique_inputs;
-  for (const GField &input_field : oper

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list