[Bf-blender-cvs] [d1ccc5b9694] master: Geometry Nodes: Add initializer for attribute creation

Hans Goudey noreply at git.blender.org
Thu Apr 22 16:20:16 CEST 2021


Commit: d1ccc5b9694b7c737158f4d4bd83ae780b32d258
Author: Hans Goudey
Date:   Thu Apr 22 09:20:03 2021 -0500
Branches: master
https://developer.blender.org/rBd1ccc5b9694b7c737158f4d4bd83ae780b32d258

Geometry Nodes: Add initializer for attribute creation

Previously we always had to set attribute values after creating
the attribute. This patch adds an initializer argument to
`attribute_try_create` which can fill it in a few ways, which
are explained in code comments.

This fixes T87597.

Differential Revision: https://developer.blender.org/D11045

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

M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/blenkernel/intern/attribute_access_intern.hh
M	source/blender/blenkernel/intern/geometry_component_mesh.cc
M	source/blender/blenkernel/intern/geometry_set_instances.cc

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

diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index e9545cba1f1..027338a5d5c 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -69,6 +69,65 @@ struct AttributeMetaData {
 using AttributeForeachCallback = blender::FunctionRef<bool(blender::StringRefNull attribute_name,
                                                            const AttributeMetaData &meta_data)>;
 
+/**
+ * Base class for the attribute intializer types described below.
+ */
+struct AttributeInit {
+  enum class Type {
+    Default,
+    VArray,
+    MoveArray,
+  };
+  Type type;
+  AttributeInit(const Type type) : type(type)
+  {
+  }
+};
+
+/**
+ * Create an attribute using the default value for the data type.
+ * The default values may depend on the attribute provider implementation.
+ */
+struct AttributeInitDefault : public AttributeInit {
+  AttributeInitDefault() : AttributeInit(Type::Default)
+  {
+  }
+};
+
+/**
+ * Create an attribute by copying data from an existing virtual array. The virtual array
+ * must have the same type as the newly created attribute.
+ *
+ * Note that this can be used to fill the new attribute with the default
+ */
+struct AttributeInitVArray : public AttributeInit {
+  const blender::fn::GVArray *varray;
+
+  AttributeInitVArray(const blender::fn::GVArray *varray)
+      : AttributeInit(Type::VArray), varray(varray)
+  {
+  }
+};
+
+/**
+ * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data.
+ * Sometimes data is created before a geometry component is available. In that case, it's
+ * preferable to move data directly to the created attribute to avoid a new allocation and a copy.
+ *
+ * Note that this will only have a benefit for attributes that are stored directly as contigious
+ * arrays, so not for some built-in attributes.
+ *
+ * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it
+ * can't be used directly, and that is generally how Blender expects custom data to be allocated.
+ */
+struct AttributeInitMove : public AttributeInit {
+  void *data = nullptr;
+
+  AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data)
+  {
+  }
+};
+
 /**
  * This is the base class for specialized geometry component types.
  */
@@ -137,11 +196,13 @@ class GeometryComponent {
   /* Returns true when the attribute has been created. */
   bool attribute_try_create(const blender::StringRef attribute_name,
                             const AttributeDomain domain,
-                            const CustomDataType data_type);
+                            const CustomDataType data_type,
+                            const AttributeInit &initializer);
 
   /* Try to create the builtin attribute with the given name. No data type or domain has to be
    * provided, because those are fixed for builtin attributes. */
-  bool attribute_try_create_builtin(const blender::StringRef attribute_name);
+  bool attribute_try_create_builtin(const blender::StringRef attribute_name,
+                                    const AttributeInit &initializer);
 
   blender::Set<std::string> attribute_names() const;
   bool attribute_foreach(const AttributeForeachCallback callback) const;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 571763e3719..6c37d34dc9b 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -254,7 +254,43 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
   return delete_success;
 }
 
-bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const
+static bool add_custom_data_layer_from_attribute_init(CustomData &custom_data,
+                                                      const CustomDataType data_type,
+                                                      const int domain_size,
+                                                      const AttributeInit &initializer)
+{
+  switch (initializer.type) {
+    case AttributeInit::Type::Default: {
+      void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+      return data != nullptr;
+    }
+    case AttributeInit::Type::VArray: {
+      void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
+      if (data == nullptr) {
+        return false;
+      }
+      const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+      varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
+      return true;
+    }
+    case AttributeInit::Type::MoveArray: {
+      void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+      void *data = CustomData_add_layer(
+          &custom_data, data_type, CD_ASSIGN, source_data, domain_size);
+      if (data == nullptr) {
+        MEM_freeN(source_data);
+        return false;
+      }
+      return true;
+    }
+  }
+
+  BLI_assert_unreachable();
+  return false;
+}
+
+bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
+                                                const AttributeInit &initializer) const
 {
   if (createable_ != Creatable) {
     return false;
@@ -267,10 +303,10 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) co
     /* Exists already. */
     return false;
   }
+
   const int domain_size = component.attribute_domain_size(domain_);
-  const void *data = CustomData_add_layer(
-      custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
-  const bool success = data != nullptr;
+  const bool success = add_custom_data_layer_from_attribute_init(
+      *custom_data, stored_type_, domain_size, initializer);
   if (success) {
     custom_data_access_.update_custom_data_pointers(component);
   }
@@ -372,10 +408,52 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
   return false;
 }
 
+static bool add_named_custom_data_layer_from_attribute_init(const StringRef attribute_name,
+                                                            CustomData &custom_data,
+                                                            const CustomDataType data_type,
+                                                            const int domain_size,
+                                                            const AttributeInit &initializer)
+{
+  char attribute_name_c[MAX_NAME];
+  attribute_name.copy(attribute_name_c);
+
+  switch (initializer.type) {
+    case AttributeInit::Type::Default: {
+      void *data = CustomData_add_layer_named(
+          &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+      return data != nullptr;
+    }
+    case AttributeInit::Type::VArray: {
+      void *data = CustomData_add_layer_named(
+          &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+      if (data == nullptr) {
+        return false;
+      }
+      const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+      varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
+      return true;
+    }
+    case AttributeInit::Type::MoveArray: {
+      void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+      void *data = CustomData_add_layer_named(
+          &custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_name_c);
+      if (data == nullptr) {
+        MEM_freeN(source_data);
+        return false;
+      }
+      return true;
+    }
+  }
+
+  BLI_assert_unreachable();
+  return false;
+}
+
 bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
                                              const StringRef attribute_name,
                                              const AttributeDomain domain,
-                                             const CustomDataType data_type) const
+                                             const CustomDataType data_type,
+                                             const AttributeInit &initializer) const
 {
   if (domain_ != domain) {
     return false;
@@ -393,10 +471,8 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
     }
   }
   const int domain_size = component.attribute_domain_size(domain_);
-  char attribute_name_c[MAX_NAME];
-  attribute_name.copy(attribute_name_c);
-  CustomData_add_layer_named(
-      custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+  add_named_custom_data_layer_from_attribute_init(
+      attribute_name, *custom_data, data_type, domain_size, initializer);
   return true;
 }
 
@@ -621,7 +697,8 @@ bool GeometryComponent::attribute_try_delete(const StringRef attribute_name)
 
 bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
                                              const AttributeDomain domain,
-                                             const CustomDataType data_type)
+                                             const CustomDataType data_type,
+                                             const AttributeInit &initializer)
 {
   using namespace blender::bke;
   if (attribute_name.is_empty()) {
@@ -640,18 +717,19 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
     if (builtin_provider->data_type() != data_type) {
       return false;
     }
-    return builtin_provider->try_create(*this);
+    return builtin_provider->try_create(*this, initializer);
   }
   for (const DynamicAttributesProvider *dynamic_provider :
        providers->dynamic_attribute_providers()) {
-    if (dynamic_provider->try_create(*this, attribute_name, domain, data_type)) {
+    if (dynamic_provider->try_create(*this, attribute_name, domain, data_type, initializer)) {
       return true;
     }
   }
   return false;
 }
 
-bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name)
+bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef att

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list