[Bf-blender-cvs] [3b71133dc54] virtual-array-attributes: better output attribute

Jacques Lucke noreply at git.blender.org
Thu Apr 15 16:13:11 CEST 2021


Commit: 3b71133dc549bb81add60ab55d142fe5f899664a
Author: Jacques Lucke
Date:   Thu Apr 15 16:02:20 2021 +0200
Branches: virtual-array-attributes
https://developer.blender.org/rB3b71133dc549bb81add60ab55d142fe5f899664a

better output attribute

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

M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/intern/attribute_access.cc

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

diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 56e7b6d407c..491607f641c 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -135,6 +135,8 @@ class GeometryComponent {
                             const AttributeDomain domain,
                             const CustomDataType data_type);
 
+  bool attribute_try_create_builtin(const blender::StringRef attribute_name);
+
   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 2824926e732..d013fb4e060 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -651,6 +651,21 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
   return false;
 }
 
+bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name)
+{
+  using namespace blender::bke;
+  if (attribute_name.is_empty()) {
+    return false;
+  }
+  const ComponentAttributeProviders *providers = this->get_attribute_providers();
+  if (providers == nullptr) {
+    return false;
+  }
+  const BuiltinAttributeProvider *builtin_provider =
+      providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
+  return builtin_provider->try_create(*this);
+}
+
 Set<std::string> GeometryComponent::attribute_names() const
 {
   Set<std::string> attributes;
@@ -787,21 +802,6 @@ std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read
   return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value);
 }
 
-blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output(
-    const StringRef attribute_name,
-    const AttributeDomain domain,
-    const CustomDataType data_type,
-    const void *default_value)
-{
-  const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
-  BLI_assert(cpp_type != nullptr);
-
-  blender::bke::WriteAttributeLookup attribute = this->attribute_try_get_for_write(attribute_name);
-  UNUSED_VARS(attribute, cpp_type);
-  /* TODO */
-  return {};
-}
-
 class GVMutableAttribute_For_OutputAttribute
     : public blender::fn::GVMutableArray_For_GMutableSpan {
  public:
@@ -855,51 +855,94 @@ static void save_output_attribute(blender::bke::OutputAttribute &output_attribut
   }
 }
 
-blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
+static blender::bke::OutputAttribute create_output_attribute(
+    GeometryComponent &component,
     const blender::StringRef attribute_name,
     const AttributeDomain domain,
-    const CustomDataType data_type)
+    const CustomDataType data_type,
+    const bool ignore_old_values,
+    const void *default_value)
 {
   using namespace blender;
   using namespace blender::fn;
   using namespace blender::bke;
   const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
   BLI_assert(cpp_type != nullptr);
-
-  WriteAttributeLookup attribute = this->attribute_try_get_for_write(attribute_name);
-  if (attribute) {
-    if (attribute.domain == domain) {
-      if (attribute.varray->type() == *cpp_type) {
-        /* Best case, attribute with correct type and domain exists already. */
-        return OutputAttribute(std::move(attribute.varray), domain, {}, true);
-      }
-      if (this->attribute_is_builtin(attribute_name)) {
-        /* Builtin types cannot change their data type and domain. Try to adapt the data type for
-         * the caller. */
-        const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
-        std::unique_ptr<GVMutableArray> varray = conversions.try_convert(
-            std::move(attribute.varray), *cpp_type);
-        return OutputAttribute(std::move(varray), domain, {}, true);
+  const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
+
+  if (component.attribute_is_builtin(attribute_name)) {
+    WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
+    if (!attribute) {
+      component.attribute_try_create_builtin(attribute_name);
+      attribute = component.attribute_try_get_for_write(attribute_name);
+      if (!attribute) {
+        /* Builtin attribute does not exist and can't be created. */
+        return {};
       }
     }
+    if (attribute.domain != domain) {
+      /* Builtin attribute is on different domain. */
+      return {};
+    }
+    std::unique_ptr<GVMutableArray> varray = std::move(attribute.varray);
+    if (varray->type() == *cpp_type) {
+      /* Builtin attribute matches exactly. */
+      return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
+    }
+    /* Builtin attribute is on the same domain but has a different data type. */
+    varray = conversions.try_convert(std::move(varray), *cpp_type);
+    return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
   }
-  else {
-    if (this->attribute_try_create(attribute_name, domain, data_type)) {
-      /* There is no conflicting attribute, so create it and return the new attribute. */
-      attribute = this->attribute_try_get_for_write(attribute_name);
-      return OutputAttribute(std::move(attribute.varray), domain, {}, true);
+
+  WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
+  if (!attribute) {
+    component.attribute_try_create(attribute_name, domain, data_type);
+    attribute = component.attribute_try_get_for_write(attribute_name);
+    if (!attribute) {
+      /* Can't create the attribute. */
+      return {};
     }
-    /* The attribute does not exist and can't be created. */
-    return {};
+  }
+  if (attribute.domain == domain && attribute.varray->type() == *cpp_type) {
+    /* Existing generic attribute matches exactly. */
+    return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values);
   }
 
-  const int domain_size = this->attribute_domain_size(domain);
+  const int domain_size = component.attribute_domain_size(domain);
+  /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
+   * attribute after processing is done. */
   void *data = MEM_mallocN_aligned(
       cpp_type->size() * domain_size, cpp_type->alignment(), __func__);
-  cpp_type->construct_default_n(data, domain);
+  if (ignore_old_values) {
+    /* This does nothing for trivially constructible types, but is necessary for correctness. */
+    cpp_type->construct_default_n(data, domain);
+  }
+  else {
+    /* Fill the temporary array with values from the existing attribute. */
+    std::unique_ptr<GVArray> old_varray = component.attribute_get_for_read(
+        attribute_name, domain, data_type, default_value);
+    old_varray->materialize_to_uninitialized(IndexRange(domain_size), data);
+  }
   std::unique_ptr<GVMutableArray> varray =
       std::make_unique<GVMutableAttribute_For_OutputAttribute>(
-          GMutableSpan{*cpp_type, data, domain_size}, *this, attribute_name);
+          GMutableSpan{*cpp_type, data, domain_size}, component, attribute_name);
 
   return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
 }
+
+blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output(
+    const StringRef attribute_name,
+    const AttributeDomain domain,
+    const CustomDataType data_type,
+    const void *default_value)
+{
+  return create_output_attribute(*this, attribute_name, domain, data_type, false, default_value);
+}
+
+blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
+    const blender::StringRef attribute_name,
+    const AttributeDomain domain,
+    const CustomDataType data_type)
+{
+  return create_output_attribute(*this, attribute_name, domain, data_type, true, nullptr);
+}



More information about the Bf-blender-cvs mailing list