[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