[Bf-blender-cvs] [8be217ada57] master: Geometry Nodes: add field node type for constants
Jacques Lucke
noreply at git.blender.org
Sun Jan 2 14:28:13 CET 2022
Commit: 8be217ada5754b065723dc85c250cf2b60f14e2e
Author: Jacques Lucke
Date: Sun Jan 2 14:27:16 2022 +0100
Branches: master
https://developer.blender.org/rB8be217ada5754b065723dc85c250cf2b60f14e2e
Geometry Nodes: add field node type for constants
It is common to have fields that contain a constant value. Before this
commit, such constants were represented by operation nodes which
don't have inputs. Having a special node type for constants makes
working with them a bit cheaper.
It also allows skipping some unnecessary processing when evaluating
fields, because constant fields can be detected more easily.
This commit also generalizes the concept of field node types a bit.
===================================================================
M source/blender/functions/FN_field.hh
M source/blender/functions/FN_multi_function_procedure.hh
M source/blender/functions/intern/field.cc
===================================================================
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index a591aaed34a..b8cb05fecab 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -59,12 +59,22 @@ namespace blender::fn {
class FieldInput;
struct FieldInputs;
+/**
+ * Have a fixed set of base node types, because all code that works with field nodes has to
+ * understand those.
+ */
+enum class FieldNodeType {
+ Input,
+ Operation,
+ Constant,
+};
+
/**
* A node in a field-tree. It has at least one output that can be referenced by fields.
*/
class FieldNode {
private:
- bool is_input_;
+ FieldNodeType node_type_;
protected:
/**
@@ -76,14 +86,13 @@ class FieldNode {
std::shared_ptr<const FieldInputs> field_inputs_;
public:
- FieldNode(bool is_input);
+ FieldNode(FieldNodeType node_type);
virtual ~FieldNode() = default;
virtual const CPPType &output_cpp_type(int output_index) const = 0;
- bool is_input() const;
- bool is_operation() const;
+ FieldNodeType node_type() const;
bool depends_on_input() const;
const std::shared_ptr<const FieldInputs> &field_inputs() const;
@@ -267,6 +276,20 @@ class FieldInput : public FieldNode {
const CPPType &output_cpp_type(int output_index) const override;
};
+class FieldConstant : public FieldNode {
+ private:
+ const CPPType &type_;
+ void *value_;
+
+ public:
+ FieldConstant(const CPPType &type, const void *value);
+ ~FieldConstant();
+
+ const CPPType &output_cpp_type(int output_index) const override;
+ const CPPType &type() const;
+ const GPointer value() const;
+};
+
/**
* Keeps track of the inputs of a field.
*/
@@ -468,9 +491,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));
- return Field<T>{GField{std::move(operation), 0}};
+ return make_constant_field(CPPType::get<T>(), &value);
}
GField make_constant_field(const CPPType &type, const void *value);
@@ -552,18 +573,13 @@ template<typename T> struct ValueOrField {
/** \name #FieldNode Inline Methods
* \{ */
-inline FieldNode::FieldNode(bool is_input) : is_input_(is_input)
-{
-}
-
-inline bool FieldNode::is_input() const
+inline FieldNode::FieldNode(const FieldNodeType node_type) : node_type_(node_type)
{
- return is_input_;
}
-inline bool FieldNode::is_operation() const
+inline FieldNodeType FieldNode::node_type() const
{
- return !is_input_;
+ return node_type_;
}
inline bool FieldNode::depends_on_input() const
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index a26eb1045a7..d73bc089278 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -268,6 +268,7 @@ class MFProcedure : NonCopyable, NonMovable {
Vector<MFReturnInstruction *> return_instructions_;
Vector<MFVariable *> variables_;
Vector<MFParameter> params_;
+ Vector<destruct_ptr<MultiFunction>> owned_functions_;
MFInstruction *entry_ = nullptr;
friend class MFProcedureDotExport;
@@ -284,9 +285,10 @@ class MFProcedure : NonCopyable, NonMovable {
MFReturnInstruction &new_return_instruction();
void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable);
-
Span<ConstMFParameter> params() const;
+ template<typename T, typename... Args> const MultiFunction &construct_function(Args &&...args);
+
MFInstruction *entry();
const MFInstruction *entry() const;
void set_entry(MFInstruction &entry);
@@ -550,6 +552,15 @@ inline Span<const MFVariable *> MFProcedure::variables() const
return variables_;
}
+template<typename T, typename... Args>
+inline const MultiFunction &MFProcedure::construct_function(Args &&...args)
+{
+ destruct_ptr<T> fn = allocator_.construct<T>(std::forward<Args>(args)...);
+ const MultiFunction &fn_ref = *fn;
+ owned_functions_.append(std::move(fn));
+ return fn_ref;
+}
+
/** \} */
} // namespace blender::fn
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 604e5c6d13f..6a4d46c14f2 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -64,17 +64,26 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields)
while (!fields_to_check.is_empty()) {
GFieldRef field = fields_to_check.pop();
- if (field.node().is_input()) {
- const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
- field_tree_info.deduplicated_field_inputs.add(field_input);
- continue;
- }
- BLI_assert(field.node().is_operation());
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- for (const GFieldRef operation_input : operation.inputs()) {
- field_tree_info.field_users.add(operation_input, field);
- if (handled_fields.add(operation_input)) {
- fields_to_check.push(operation_input);
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ const FieldInput &field_input = static_cast<const FieldInput &>(field_node);
+ field_tree_info.deduplicated_field_inputs.add(field_input);
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation = static_cast<const FieldOperation &>(field_node);
+ for (const GFieldRef operation_input : operation.inputs()) {
+ field_tree_info.field_users.add(operation_input, field);
+ if (handled_fields.add(operation_input)) {
+ fields_to_check.push(operation_input);
+ }
+ }
+ break;
+ }
+ case FieldNodeType::Constant: {
+ /* Nothing to do. */
+ break;
}
}
}
@@ -179,56 +188,71 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
fields_to_check.pop();
continue;
}
- /* Field inputs should already be handled above. */
- BLI_assert(field.node().is_operation());
-
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- const Span<GField> operation_inputs = operation.inputs();
-
- if (field_with_index.current_input_index < operation_inputs.size()) {
- /* Not all inputs are handled yet. Push the next input field to the stack and increment the
- * input index. */
- fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
- field_with_index.current_input_index++;
- }
- else {
- /* All inputs variables are ready, now gather all variables that are used by the function
- * and call it. */
- const MultiFunction &multi_function = operation.multi_function();
- Vector<MFVariable *> variables(multi_function.param_amount());
-
- int param_input_index = 0;
- int param_output_index = 0;
- for (const int param_index : multi_function.param_indices()) {
- const MFParamType param_type = multi_function.param_type(param_index);
- const MFParamType::InterfaceType interface_type = param_type.interface_type();
- if (interface_type == MFParamType::Input) {
- const GField &input_field = operation_inputs[param_input_index];
- variables[param_index] = variable_by_field.lookup(input_field);
- param_input_index++;
- }
- else if (interface_type == MFParamType::Output) {
- const GFieldRef output_field{operation, param_output_index};
- const bool output_is_ignored =
- field_tree_info.field_users.lookup(output_field).is_empty() &&
- !output_fields.contains(output_field);
- if (output_is_ignored) {
- /* Ignored outputs don't need a variable. */
- variables[param_index] = nullptr;
- }
- else {
- /* Create a new variable for used outputs. */
- MFVariable &new_variable = procedure.new_variable(param_type.data_type());
- variables[param_index] = &new_variable;
- variable_by_field.add_new(output_field, &new_variable);
- }
- param_output_index++;
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ /* Field inputs should already be handled above. */
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation_node = static_cast<const FieldOperation &>(field.node());
+ const Span<GField> operation_inputs = operation_node.inputs();
+
+ if (field_with_index.current_input_index < operation_inputs.size()) {
+ /* Not all inputs are handled yet. Push the next input field to the stack and increment
+ * the input index. */
+ fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
+ field_with_index.current_input_index++;
}
else {
- BLI_assert_unreachable();
+ /* All inputs variables are ready, now gather all variables that are used by the
+ * function and call it. */
+ const MultiFunction &multi_function = operation_node.multi_function();
+ Vector<MFVariable *> variables(multi_function.param_amount());
+
+ int param_input_index = 0;
+ int param_output_index = 0;
+ for (const int param_index : multi_function.param_indices()) {
+ const MFParamType param_type = multi_function.param_type(param_index);
+ const MFParamType::InterfaceType interface_type = param_type.interface_type();
+ if (interface_type == MFParamType::Input) {
+ const GField &input_field = operation_inputs[param_input_index];
+ variables[param_index]
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list