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 25237d2625
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
This commit is contained in:
parent
225b5a3491
commit
9088a1f476
Notes:
blender-bot
2023-02-14 06:00:46 +01:00
Referenced by commit 1fbd300adb
, Fix: Curves sculpt adding resets attribute values
|
@ -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`,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 :
|
||||
new_curves_num;
|
||||
const CPPType &type = attribute.span.type();
|
||||
GMutableSpan new_data = attribute.span.take_back(new_elements_num);
|
||||
type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
|
||||
attribute.finish();
|
||||
return true;
|
||||
});
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,24 +94,24 @@ static void expand_mesh(Mesh &mesh,
|
|||
const int loop_expand)
|
||||
{
|
||||
if (vert_expand != 0) {
|
||||
CustomData_duplicate_referenced_layers(&mesh.vdata, mesh.totvert);
|
||||
const int old_verts_num = mesh.totvert;
|
||||
mesh.totvert += vert_expand;
|
||||
CustomData_realloc(&mesh.vdata, mesh.totvert);
|
||||
CustomData_realloc(&mesh.vdata, old_verts_num, mesh.totvert);
|
||||
}
|
||||
if (edge_expand != 0) {
|
||||
CustomData_duplicate_referenced_layers(&mesh.edata, mesh.totedge);
|
||||
const int old_edges_num = mesh.totedge;
|
||||
mesh.totedge += edge_expand;
|
||||
CustomData_realloc(&mesh.edata, mesh.totedge);
|
||||
CustomData_realloc(&mesh.edata, old_edges_num, mesh.totedge);
|
||||
}
|
||||
if (poly_expand != 0) {
|
||||
CustomData_duplicate_referenced_layers(&mesh.pdata, mesh.totpoly);
|
||||
const int old_polys_num = mesh.totpoly;
|
||||
mesh.totpoly += poly_expand;
|
||||
CustomData_realloc(&mesh.pdata, mesh.totpoly);
|
||||
CustomData_realloc(&mesh.pdata, old_polys_num, mesh.totpoly);
|
||||
}
|
||||
if (loop_expand != 0) {
|
||||
CustomData_duplicate_referenced_layers(&mesh.ldata, mesh.totloop);
|
||||
const int old_loops_num = mesh.totloop;
|
||||
mesh.totloop += loop_expand;
|
||||
CustomData_realloc(&mesh.ldata, mesh.totloop);
|
||||
CustomData_realloc(&mesh.ldata, old_loops_num, mesh.totloop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,6 +147,7 @@ static MEdge new_edge(const int v1, const int v2)
|
|||
MEdge edge;
|
||||
edge.v1 = v1;
|
||||
edge.v2 = v2;
|
||||
edge.crease = 0;
|
||||
edge.flag = (ME_EDGEDRAW | ME_EDGERENDER);
|
||||
return edge;
|
||||
}
|
||||
|
@ -156,6 +157,7 @@ static MEdge new_loose_edge(const int v1, const int v2)
|
|||
MEdge edge;
|
||||
edge.v1 = v1;
|
||||
edge.v2 = v2;
|
||||
edge.crease = 0;
|
||||
edge.flag = ME_LOOSEEDGE;
|
||||
return edge;
|
||||
}
|
||||
|
@ -286,6 +288,7 @@ static void extrude_mesh_vertices(Mesh &mesh,
|
|||
for (const int i : range) {
|
||||
const float3 offset = offsets[selection[i]];
|
||||
add_v3_v3(new_verts[i].co, offset);
|
||||
new_verts[i].flag = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -608,6 +611,7 @@ static void extrude_mesh_edges(Mesh &mesh,
|
|||
threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
add_v3_v3(new_verts[i].co, offset);
|
||||
new_verts[i].flag = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -615,6 +619,7 @@ static void extrude_mesh_edges(Mesh &mesh,
|
|||
threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
add_v3_v3(new_verts[i].co, vert_offsets[new_vert_indices[i]]);
|
||||
new_verts[i].flag = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -996,6 +1001,10 @@ static void extrude_mesh_face_regions(Mesh &mesh,
|
|||
});
|
||||
}
|
||||
|
||||
for (MVert &vert : verts.slice(new_vert_range)) {
|
||||
vert.flag = 0;
|
||||
}
|
||||
|
||||
MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
|
||||
vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
|
||||
|
||||
|
@ -1253,6 +1262,7 @@ static void extrude_individual_mesh_faces(Mesh &mesh,
|
|||
const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
|
||||
for (MVert &vert : new_verts.slice(poly_corner_range)) {
|
||||
add_v3_v3(vert.co, poly_offset[poly_selection[i_selection]]);
|
||||
vert.flag = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue