BMesh: Improve performance when copying attributes in same mesh

When the BMesh source and result arguments are the same, restore
performance lost by 9175d9b7c2, which made copying layers
have quadratic time complexity. When we know the custom data format
is the same between the source and result, the copying can be much
simpler, so it's worth specializing this case. There is still more
to be done, because often we only know that the two meshes are the
same at runtime. A followup commit will add that check.

The quadratic runtime means performance is fine for low layer counts,
and terrible with higher layer counts. For example, in my testing with
47 boolean attributes, copying 250k vertices went from 2.3 seconds to
316 ms.

The implementation uses a new CustomData function that copies an entire
BMesh custom data block, called by a function in the BMesh module
overloaded for every BMesh element type. That handles the extra data
like flags, normals, and material indices.

Related to #115776
This commit is contained in:
Hans Goudey
2023-12-05 20:26:28 -05:00
parent cc7080b8b0
commit 66da875488
4 changed files with 63 additions and 3 deletions

View File

@@ -347,6 +347,11 @@ void CustomData_bmesh_copy_data(const CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block);
/**
* Copy all layers from the sourde to the destination block. Allocate the result block if
* necessary, otherwise free its existing layer data.
*/
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block);
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest,
void *src_block,

View File

@@ -3899,6 +3899,35 @@ void CustomData_bmesh_copy_data(const CustomData *source,
CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0);
}
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)
{
if (*dst_block) {
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
const LayerTypeInfo &info = *layerType_getInfo(eCustomDataType(layer.type));
if (info.free) {
info.free(POINTER_OFFSET(*dst_block, layer.offset), 1);
}
}
}
else {
if (data.totsize == 0) {
return;
}
*dst_block = BLI_mempool_alloc(data.pool);
}
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
const int offset = layer.offset;
const LayerTypeInfo &info = *layerType_getInfo(eCustomDataType(layer.type));
if (info.copy) {
info.copy(POINTER_OFFSET(src_block, offset), POINTER_OFFSET(*dst_block, offset), 1);
}
else {
memcpy(POINTER_OFFSET(*dst_block, offset), POINTER_OFFSET(src_block, offset), info.size);
}
}
}
void *CustomData_bmesh_get(const CustomData *data, void *block, const eCustomDataType type)
{
int layer_index = CustomData_get_active_layer_index(data, type);

View File

@@ -443,9 +443,32 @@ void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void
BM_elem_attrs_copy_ex(bm_src, bm_dst, ele_src, ele_dst, BM_ELEM_SELECT, 0x0);
}
void BM_elem_attrs_copy(BMesh &bm, const void *ele_src, void *ele_dst)
void BM_elem_attrs_copy(BMesh &bm, const BMVert *src, BMVert *dst)
{
BM_elem_attrs_copy_ex(&bm, &bm, ele_src, ele_dst, BM_ELEM_SELECT, 0x0);
BLI_assert(src != dst);
CustomData_bmesh_copy_block(bm.vdata, src->head.data, &dst->head.data);
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
copy_v3_v3(dst->no, src->no);
}
void BM_elem_attrs_copy(BMesh &bm, const BMEdge *src, BMEdge *dst)
{
BLI_assert(src != dst);
CustomData_bmesh_copy_block(bm.edata, src->head.data, &dst->head.data);
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
}
void BM_elem_attrs_copy(BMesh &bm, const BMFace *src, BMFace *dst)
{
BLI_assert(src != dst);
CustomData_bmesh_copy_block(bm.pdata, src->head.data, &dst->head.data);
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
copy_v3_v3(dst->no, src->no);
dst->mat_nr = src->mat_nr;
}
void BM_elem_attrs_copy(BMesh &bm, const BMLoop *src, BMLoop *dst)
{
BLI_assert(src != dst);
CustomData_bmesh_copy_block(bm.ldata, src->head.data, &dst->head.data);
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
}
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)

View File

@@ -134,7 +134,10 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src,
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
/** Copy attributes between elements in the same BMesh. */
void BM_elem_attrs_copy(BMesh &bm, const void *ele_src, void *ele_dst);
void BM_elem_attrs_copy(BMesh &bm, const BMVert *src, BMVert *dst);
void BM_elem_attrs_copy(BMesh &bm, const BMEdge *src, BMEdge *dst);
void BM_elem_attrs_copy(BMesh &bm, const BMFace *src, BMFace *dst);
void BM_elem_attrs_copy(BMesh &bm, const BMLoop *src, BMLoop *dst);
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v);