[Bf-blender-cvs] [9088a1f4764] master: Geometry: Avoid unnecessary initialization when resizing data arrays

Hans Goudey noreply at git.blender.org
Mon Sep 12 18:39:50 CEST 2022


Commit: 9088a1f4764f371f7f22384e7d7e2c8971d5c9f0
Author: Hans Goudey
Date:   Mon Sep 12 11:35:33 2022 -0500
Branches: master
https://developer.blender.org/rB9088a1f4764f371f7f22384e7d7e2c8971d5c9f0

Geometry: Avoid unnecessary initialization when resizing data arrays

When resizing mesh and curves attribute storage, avoid initializing the
new memory for basic types. Also, avoid skipping "no free" layers; all
layers should be reallocated to the new size since they may be accessed.

The semantics introduced in 25237d2625078c6d1 are essential for this
change, because otherwise we don't have a way to construct non-trivial
types in the new memory.

In a basic test of the extrude node, I observed a performance
improvement of about 30%, from 55ms to 42ms.

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

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

M	source/blender/blenkernel/BKE_customdata.h
M	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/blenkernel/intern/curves_geometry.cc
M	source/blender/blenkernel/intern/customdata.cc
M	source/blender/blenkernel/intern/mesh.cc
M	source/blender/blenkernel/intern/mesh_convert.cc
M	source/blender/blenkernel/intern/pointcloud.cc
M	source/blender/geometry/intern/add_curves_on_mesh.cc
M	source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc

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

diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 09d37682b3c..24fa5f0e87a 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -178,13 +178,11 @@ bool CustomData_merge_mesh_to_bmesh(const struct CustomData *source,
                                     int totelem);
 
 /**
- * Reallocate custom data to a new element count.
- * Only affects on data layers which are owned by the CustomData itself,
- * referenced data is kept unchanged,
- *
- * \note Take care of referenced layers by yourself!
+ * Reallocate custom data to a new element count. If the new size is larger, the new values use
+ * the #CD_CONSTRUCT behavior, so trivial types must be initialized by the caller. After being
+ * resized, the #CustomData does not contain any referenced layers.
  */
-void CustomData_realloc(struct CustomData *data, int totelem);
+void CustomData_realloc(struct CustomData *data, int old_size, int new_size);
 
 /**
  * BMesh version of CustomData_merge; merges the layouts of source and `dest`,
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 69f3e5bb389..27c54a3d4a7 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -726,8 +726,22 @@ bool CustomDataAttributes::remove(const AttributeIDRef &attribute_id)
 
 void CustomDataAttributes::reallocate(const int size)
 {
+  const int old_size = size_;
   size_ = size;
-  CustomData_realloc(&data, size);
+  CustomData_realloc(&data, old_size, size_);
+  if (size_ > old_size) {
+    /* Fill default new values. */
+    const int new_elements_num = size_ - old_size;
+    this->foreach_attribute(
+        [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) {
+          GMutableSpan new_data = this->get_for_write(id)->take_back(new_elements_num);
+          const CPPType &type = new_data.type();
+          type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
+          return true;
+        },
+        /* Dummy. */
+        ATTR_DOMAIN_POINT);
+  }
 }
 
 void CustomDataAttributes::clear()
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 35b209179d3..d192c10912f 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -963,11 +963,11 @@ void CurvesGeometry::ensure_can_interpolate_to_evaluated() const
 void CurvesGeometry::resize(const int points_num, const int curves_num)
 {
   if (points_num != this->point_num) {
-    CustomData_realloc(&this->point_data, points_num);
+    CustomData_realloc(&this->point_data, this->points_num(), points_num);
     this->point_num = points_num;
   }
   if (curves_num != this->curve_num) {
-    CustomData_realloc(&this->curve_data, curves_num);
+    CustomData_realloc(&this->curve_data, this->curves_num(), curves_num);
     this->curve_num = curves_num;
     this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1));
   }
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 24373053896..82a1a2aa8f6 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -2408,19 +2408,37 @@ bool CustomData_merge_mesh_to_bmesh(const CustomData *source,
   return result;
 }
 
-void CustomData_realloc(CustomData *data, const int totelem)
+void CustomData_realloc(CustomData *data, const int old_size, const int new_size)
 {
-  BLI_assert(totelem >= 0);
+  BLI_assert(new_size >= 0);
   for (int i = 0; i < data->totlayer; i++) {
     CustomDataLayer *layer = &data->layers[i];
-    const LayerTypeInfo *typeInfo;
+    const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+
+    const int64_t old_size_in_bytes = int64_t(old_size) * typeInfo->size;
+    const int64_t new_size_in_bytes = int64_t(new_size) * typeInfo->size;
     if (layer->flag & CD_FLAG_NOFREE) {
-      continue;
+      const void *old_data = layer->data;
+      layer->data = MEM_malloc_arrayN(new_size, typeInfo->size, __func__);
+      if (typeInfo->copy) {
+        typeInfo->copy(old_data, layer->data, std::min(old_size, new_size));
+      }
+      else {
+        std::memcpy(layer->data, old_data, std::min(old_size_in_bytes, new_size_in_bytes));
+      }
+      layer->flag &= ~CD_FLAG_NOFREE;
+    }
+    else {
+      layer->data = MEM_reallocN(layer->data, new_size_in_bytes);
+    }
+
+    if (new_size > old_size) {
+      /* Initialize new values for non-trivial types. */
+      if (typeInfo->construct) {
+        const int new_elements_num = new_size - old_size;
+        typeInfo->construct(POINTER_OFFSET(layer->data, old_size_in_bytes), new_elements_num);
+      }
     }
-    typeInfo = layerType_getInfo(layer->type);
-    /* Use calloc to avoid the need to manually initialize new data in layers.
-     * Useful for types like #MDeformVert which contain a pointer. */
-    layer->data = MEM_recallocN(layer->data, (size_t)totelem * typeInfo->size);
   }
 }
 
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index a0548b7efd4..636be0dc032 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -2095,11 +2095,11 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
     const bool do_edges = (num_new_edges > 0);
 
     /* Reallocate all vert and edge related data. */
+    CustomData_realloc(&mesh->vdata, mesh->totvert, mesh->totvert + num_new_verts);
     mesh->totvert += num_new_verts;
-    CustomData_realloc(&mesh->vdata, mesh->totvert);
     if (do_edges) {
+      CustomData_realloc(&mesh->edata, mesh->totedge, mesh->totedge + num_new_edges);
       mesh->totedge += num_new_edges;
-      CustomData_realloc(&mesh->edata, mesh->totedge);
     }
 
     /* Update normals manually to avoid recalculation after this operation. */
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index b7d8972aa7b..e56df0e3fe3 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -105,8 +105,9 @@ static void make_edges_mdata_extend(Mesh &mesh)
 #endif
 
   if (totedge_new) {
-    CustomData_realloc(&mesh.edata, totedge + totedge_new);
-
+    /* The only layer should be edges, so no other layers need to be initialized. */
+    BLI_assert(mesh.edata.totlayer == 1);
+    CustomData_realloc(&mesh.edata, totedge, totedge + totedge_new);
     mesh.totedge += totedge_new;
     MutableSpan<MEdge> edges = mesh.edges_for_write();
     MEdge *medge = &edges[totedge];
@@ -634,9 +635,11 @@ void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud)
   using namespace blender;
 
   BLI_assert(me != nullptr);
-
+  /* The pointcloud should only contain the position attribute, otherwise more attributes would
+   * need to be initialized below. */
+  BLI_assert(pointcloud->attributes().all_ids().size() == 1);
+  CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint, me->totvert);
   pointcloud->totpoint = me->totvert;
-  CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
 
   /* Copy over all attributes. */
   CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert);
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index fe6353bc72d..b45e164b594 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -189,8 +189,9 @@ IDTypeInfo IDType_ID_PT = {
 
 static void pointcloud_random(PointCloud *pointcloud)
 {
+  BLI_assert(pointcloud->totpoint == 0);
   pointcloud->totpoint = 400;
-  CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
+  CustomData_realloc(&pointcloud->pdata, 0, pointcloud->totpoint);
 
   RNG *rng = BLI_rng_new(0);
 
@@ -238,9 +239,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
       nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE));
 
   pointcloud_init_data(&pointcloud->id);
-
-  pointcloud->totpoint = totpoint;
-
   CustomData_add_layer_named(&pointcloud->pdata,
                              CD_PROP_FLOAT,
                              CD_SET_DEFAULT,
@@ -248,8 +246,8 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
                              pointcloud->totpoint,
                              POINTCLOUD_ATTR_RADIUS);
 
+  CustomData_realloc(&pointcloud->pdata, 0, totpoint);
   pointcloud->totpoint = totpoint;
-  CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
 
   return pointcloud;
 }
diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc
index e06ee55afa0..bb5e2a0a28a 100644
--- a/source/blender/geometry/intern/add_curves_on_mesh.cc
+++ b/source/blender/geometry/intern/add_curves_on_mesh.cc
@@ -372,6 +372,28 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
 
   curves.fill_curve_types(new_curves_range, CURVE_TYPE_CATMULL_ROM);
 
+  /* Explicitly set all other attributes besides those processed above to default values. */
+  bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
+  Set<std::string> attributes_to_skip{{"position",
+                                       "curve_type",
+                                       "surface_uv_coordinate",
+                                       ".selection_point_float",
+                                       ".selection_curve_float"}};
+  attributes.for_all(
+      [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) {
+        if (id.is_named() && attributes_to_skip.contains(id.name())) {
+          return true;
+        }
+        bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
+        const int new_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? new_points_num :
+  

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list