[Bf-blender-cvs] [866a56f76ef] geometry-nodes: Geometry Nodes: initial generic attribute access API

Jacques Lucke noreply at git.blender.org
Wed Nov 18 12:29:18 CET 2020


Commit: 866a56f76ef43bd631789659c4bbbf05b89024f8
Author: Jacques Lucke
Date:   Wed Nov 18 12:20:54 2020 +0100
Branches: geometry-nodes
https://developer.blender.org/rB866a56f76ef43bd631789659c4bbbf05b89024f8

Geometry Nodes: initial generic attribute access API

I will have to do a couple more iterations on this api in the upcoming weeks,
but for now it should be good enough.

The API adds an indirection for attribute access. That has the following benefits:
* Most code does not have to care about how an attribute is stored internally.
  This is mainly necessary, because we have to deal with "legacy" attributes
  such as vertex weights and attributes that are embedded into other structs
  such as vertex positions.
* When reading from an attribute, we generally don't care what domain the
  attribute is stored on. So we want to abstract away the interpolation that
  that adapts attributes from one domain to another domain (this is not
  actually implemented yet).

Accessing attributes through this indirection does have a performance penalty.
In later iterations of this API I want to reduce this penalty and extend the API
so that performance critical code does not have to go through the indirection
for every attribute access.

Other possible improvements for later iterations include:
* Actually implement interpolation between domains.
* Don't use inheritance for the different attribute types. A single class for read
  access and one for write access might be enough, because we know all the ways
  in which attributes are stored internally. We don't want more different internal
  structures in the future. On the contrary, ideally we can consolidate the different
  storage formats in the future to reduce the need for this indirection.
* Remove the need for heap allocations when creating attribute accessors.

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

A	source/blender/blenkernel/BKE_attribute_access.hh
M	source/blender/blenkernel/CMakeLists.txt
A	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/nodes/NOD_geometry_exec.hh

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

diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
new file mode 100644
index 00000000000..41f5a1a3605
--- /dev/null
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -0,0 +1,260 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "FN_cpp_type.hh"
+
+#include "BKE_attribute.h"
+#include "BKE_geometry_set.hh"
+
+struct Mesh;
+
+namespace blender::bke {
+
+using fn::CPPType;
+
+/**
+ * This class offers an indirection for reading an attribute.
+ * This is useful for the following reasons:
+ * - Blender does not store all attributes the same way.
+ *   The simplest case are custom data layers with primitive types.
+ *   A bit more complex are mesh attributes like the position of vertices,
+ *   which are embedded into the MVert struct.
+ *   Even more complex to access are vertex weights.
+ * - Sometimes attributes are stored on one domain, but we want to access
+ *   the attribute on a different domain. Therefore, we have to interpolate
+ *   between the domains.
+ */
+class ReadAttribute {
+ protected:
+  const AttributeDomain domain_;
+  const CPPType &cpp_type_;
+  const int64_t size_;
+
+ public:
+  ReadAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
+      : domain_(domain), cpp_type_(cpp_type), size_(size)
+  {
+  }
+
+  virtual ~ReadAttribute();
+
+  AttributeDomain domain() const
+  {
+    return domain_;
+  }
+
+  const CPPType &cpp_type() const
+  {
+    return cpp_type_;
+  }
+
+  int64_t size() const
+  {
+    return size_;
+  }
+
+  void get(const int64_t index, void *r_value) const
+  {
+    BLI_assert(index < size_);
+    this->get_internal(index, r_value);
+  }
+
+ protected:
+  /* r_value is expected to be uninitialized. */
+  virtual void get_internal(const int64_t index, void *r_value) const = 0;
+};
+
+/**
+ * This exists for similar reasons as the ReadAttribute class, except that
+ * it does not deal with interpolation between domains.
+ */
+class WriteAttribute {
+ protected:
+  const AttributeDomain domain_;
+  const CPPType &cpp_type_;
+  const int64_t size_;
+
+ public:
+  WriteAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
+      : domain_(domain), cpp_type_(cpp_type), size_(size)
+  {
+  }
+
+  virtual ~WriteAttribute();
+
+  AttributeDomain domain() const
+  {
+    return domain_;
+  }
+
+  const CPPType &cpp_type() const
+  {
+    return cpp_type_;
+  }
+
+  int64_t size() const
+  {
+    return size_;
+  }
+
+  void get(const int64_t index, void *r_value) const
+  {
+    BLI_assert(index < size_);
+    this->get_internal(index, r_value);
+  }
+
+  void set(const int64_t index, const void *value)
+  {
+    BLI_assert(index < size_);
+    this->set_internal(index, value);
+  }
+
+ protected:
+  virtual void get_internal(const int64_t index, void *r_value) const = 0;
+  virtual void set_internal(const int64_t index, const void *value) = 0;
+};
+
+using ReadAttributePtr = std::unique_ptr<ReadAttribute>;
+using WriteAttributePtr = std::unique_ptr<WriteAttribute>;
+
+/* This provides type safe access to an attribute. */
+template<typename T> class TypedReadAttribute {
+ private:
+  ReadAttributePtr attribute_;
+
+ public:
+  TypedReadAttribute(ReadAttributePtr attribute) : attribute_(std::move(attribute))
+  {
+    BLI_assert(attribute_);
+    BLI_assert(attribute_->cpp_type().is<T>());
+  }
+
+  int64_t size() const
+  {
+    return attribute_->size();
+  }
+
+  T operator[](const int64_t index) const
+  {
+    BLI_assert(index < attribute_->size());
+    T value;
+    value.~T();
+    attribute_->get(index, &value);
+    return value;
+  }
+};
+
+/* This provides type safe access to an attribute. */
+template<typename T> class TypedWriteAttribute {
+ private:
+  WriteAttributePtr attribute_;
+
+ public:
+  TypedWriteAttribute(WriteAttributePtr attribute) : attribute_(std::move(attribute))
+  {
+    BLI_assert(attribute_);
+    BLI_assert(attribute_->cpp_type().is<T>());
+  }
+
+  int64_t size() const
+  {
+    return attribute_->size();
+  }
+
+  T operator[](const int64_t index) const
+  {
+    BLI_assert(index < attribute_->size());
+    T value;
+    value.~T();
+    attribute_->get(index, &value);
+    return value;
+  }
+
+  void set(const int64_t index, const T &value)
+  {
+    attribute_->set(index, &value);
+  }
+};
+
+using FloatReadAttribute = TypedReadAttribute<float>;
+using Float3ReadAttribute = TypedReadAttribute<float3>;
+using FloatWriteAttribute = TypedWriteAttribute<float>;
+using Float3WriteAttribute = TypedWriteAttribute<float3>;
+
+/* --------------------------------------------------------------------
+ * Main attribute getters.
+ */
+
+ReadAttributePtr mesh_attribute_get_for_read(const MeshComponent &mesh_component,
+                                             const StringRef attribute_name);
+WriteAttributePtr mesh_attribute_get_for_write(MeshComponent &mesh_component,
+                                               const StringRef attribute_name);
+
+ReadAttributePtr pointcloud_attribute_get_for_read(const PointCloudComponent &pointcloud_component,
+                                                   const StringRef attribute_name);
+WriteAttributePtr pointcloud_attribute_get_for_write(
+    const PointCloudComponent &pointcloud_component, const StringRef attribute_name);
+
+/* --------------------------------------------------------------------
+ * Utilities for getting more specific attributes.
+ */
+
+ReadAttributePtr mesh_attribute_adapt_domain(const MeshComponent &mesh_component,
+                                             ReadAttributePtr attribute,
+                                             const AttributeDomain to_domain);
+
+ReadAttributePtr mesh_attribute_get_for_read(const MeshComponent &mesh_component,
+                                             const StringRef attribute_name,
+                                             const CPPType &cpp_type,
+                                             const AttributeDomain domain,
+                                             const void *default_value = nullptr);
+
+template<typename T>
+TypedReadAttribute<T> mesh_attribute_get_for_read(const MeshComponent &mesh_component,
+                                                  const StringRef attribute_name,
+                                                  const AttributeDomain domain,
+                                                  const T &default_value)
+{
+  ReadAttributePtr attribute = mesh_attribute_get_for_read(
+      mesh_component,
+      attribute_name,
+      CPPType::get<T>(),
+      domain,
+      static_cast<const void *>(&default_value));
+  BLI_assert(attribute);
+  return attribute;
+}
+
+ReadAttributePtr pointcloud_attribute_get_for_read(const PointCloudComponent &pointcloud_component,
+                                                   const StringRef attribute_name,
+                                                   const CPPType &cpp_type,
+                                                   const void *default_value = nullptr);
+
+template<typename T>
+TypedReadAttribute<T> pointcloud_attribute_get_for_read(
+    const PointCloudComponent &pointcloud_component,
+    const StringRef attribute_name,
+    const T &default_value)
+{
+  ReadAttributePtr attribute = pointcloud_attribute_get_for_read(
+      pointcloud_component, attribute_name, CPPType::get<T>(), &default_value);
+  BLI_assert(attribute);
+  return attribute;
+}
+
+}  // namespace blender::bke
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index ef093174dd5..3cd184e3a34 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -78,6 +78,7 @@ set(SRC
   intern/armature_deform.c
   intern/armature_update.c
   intern/attribute.c
+  intern/attribute_access.cc
   intern/autoexec.c
   intern/blender.c
   intern/blender_copybuffer.c
@@ -267,6 +268,7 @@ set(SRC
   BKE_appdir.h
   BKE_armature.h
   BKE_attribute.h
+  BKE_attribute_access.hh
   BKE_autoexec.h
   BKE_blender.h
   BKE_blender_copybuffer.h
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
new file mode 100644
index 00000000000..1969a511fdf
--- /dev/null
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -0,0 +1,528 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <utility>
+
+#include "BKE_attribute_access.hh"
+#include "BKE_deform.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BLI_color.hh"
+#include "BLI_float2.hh"
+#include "BLI_span.hh"
+
+namespace blender::bke {
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute accessor im

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list