Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-11-23 16:47:25 +0300
committerJacques Lucke <jacques@blender.org>2021-11-23 16:49:26 +0300
commit47276b84701727c2f187c77f1ec502b4ca4963bd (patch)
treeac6e6fced7908dbaa984cfe686b2e3a080b99fc7 /source/blender/functions/FN_field.hh
parent0bedd5d14f6d61a6a4a96cc7f88484b0dc46f752 (diff)
Geometry Nodes: reduce overhead when processing single values
Currently the geometry nodes evaluator always stores a field for every type that supports it, even if it is just a single value. This results in a lot of overhead when there are many sockets that just contain a single value, which is often the case. This introduces a new `ValueOrField<T>` type that is used by the geometry nodes evaluator. Now a field will only be created when it is actually necessary. See D13307 for more details. In extrem cases this can speed up the evaluation 2-3x (those cases are probably never hit in practice though, but it's good to get rid of unnecessary overhead nevertheless). Differential Revision: https://developer.blender.org/D13307
Diffstat (limited to 'source/blender/functions/FN_field.hh')
-rw-r--r--source/blender/functions/FN_field.hh63
1 files changed, 62 insertions, 1 deletions
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index fb488fdbfa9..28bb120bb17 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -178,11 +178,19 @@ class GFieldRef : public GFieldBase<const FieldNode *> {
}
};
+namespace detail {
+/* Utility class to make #is_field_v work. */
+struct TypedFieldBase {
+};
+} // namespace detail
+
/**
* A typed version of #GField. It has the same memory layout as #GField.
*/
-template<typename T> class Field : public GField {
+template<typename T> class Field : public GField, detail::TypedFieldBase {
public:
+ using base_type = T;
+
Field() = default;
Field(GField field) : GField(std::move(field))
@@ -196,6 +204,11 @@ template<typename T> class Field : public GField {
}
};
+/** True when T is any Field<...> type. */
+template<typename T>
+static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> &&
+ !std::is_same_v<detail::TypedFieldBase, T>;
+
/**
* A #FieldNode that allows composing existing fields into new fields.
*/
@@ -419,6 +432,8 @@ template<typename T> Field<T> make_constant_field(T value)
return Field<T>{GField{std::move(operation), 0}};
}
+GField make_constant_field(const CPPType &type, const void *value);
+
GField make_field_constant_if_possible(GField field);
class IndexFieldInput final : public FieldInput {
@@ -438,6 +453,52 @@ class IndexFieldInput final : public FieldInput {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Value or Field Class
+ *
+ * Utility class that wraps a single value and a field, to simplify accessing both of the types.
+ * \{ */
+
+template<typename T> struct ValueOrField {
+ /** Value that is used when the field is empty. */
+ T value{};
+ Field<T> field;
+
+ ValueOrField() = default;
+
+ ValueOrField(T value) : value(std::move(value))
+ {
+ }
+
+ ValueOrField(Field<T> field) : field(std::move(field))
+ {
+ }
+
+ bool is_field() const
+ {
+ return (bool)this->field;
+ }
+
+ Field<T> as_field() const
+ {
+ if (this->field) {
+ return this->field;
+ }
+ return make_constant_field(this->value);
+ }
+
+ T as_value() const
+ {
+ if (this->field) {
+ /* This returns a default value when the field is not constant. */
+ return evaluate_constant_field(this->field);
+ }
+ return this->value;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name #FieldNode Inline Methods
* \{ */