BMesh: Optimize copying attributes from many elements at once #115824

Merged
Hans Goudey merged 9 commits from HooglyBoogly/blender:bmesh-cd-copy-performance-fix into main 2023-12-09 05:37:47 +01:00
6 changed files with 286 additions and 217 deletions

View File

@ -90,6 +90,8 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask);
typedef void (*cd_interp)(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest);
typedef void (*cd_copy)(const void *source, void *dest, int count);
typedef void (*cd_set_default_value)(void *data, int count);
typedef void (*cd_free)(void *data, int count);
typedef bool (*cd_validate)(void *item, uint totitems, bool do_fixes);
/**
@ -343,20 +345,57 @@ void CustomData_copy_elements(eCustomDataType type,
void *src_data_ofs,
void *dst_data_ofs,
int count);
void CustomData_bmesh_copy_data(const CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block);
/**
* Copy all layers from the source 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,
void **dest_block,
eCustomDataMask mask_exclude);
/** Holds the minimal data necessary to copy data blocks from one custom data format to another. */
struct BMCustomDataCopyMap {
struct TrivialCopy {
int size;
int src_offset;
int dst_offset;
};
struct Copy {
cd_copy fn;
int src_offset;
int dst_offset;
};
struct TrivialDefault {
int size;
int dst_offset;
};
struct Default {
cd_set_default_value fn;
int dst_offset;
};
struct Free {
cd_free fn;
int dst_offset;
};
blender::Vector<TrivialCopy> trivial_copies;
blender::Vector<Copy> copies;
blender::Vector<TrivialDefault> trivial_defaults;
blender::Vector<Default> defaults;
blender::Vector<Free> free;
};
/** Precalculate a map for more efficient copying between custom data formats. */
BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src,
const CustomData &dst,
eCustomDataMask mask_exclude = 0);
/**
* Copy custom data layers for one element between two potentially different formats with a
* precalculated map.
*/
HooglyBoogly marked this conversation as resolved Outdated

Prefer to order the helper argument (map in this case) last, since it's the convention to have containers first bm in this case.

Prefer to order the helper argument (map in this case) last, since it's the convention to have containers first `bm` in this case.
void CustomData_bmesh_copy_block(CustomData &dst_data,
const BMCustomDataCopyMap &map,
const void *src_block,
void **dest_block);
/**
* Copies data of a single layer of a given type.

View File

@ -61,6 +61,7 @@
/* only for customdata_data_transfer_interp_normal_normals */
#include "data_transfer_intern.h"
using blender::Array;
using blender::BitVector;
using blender::float2;
using blender::ImplicitSharingInfo;
@ -139,7 +140,7 @@ struct LayerTypeInfo {
* size should be the size of one element of this layer's data (e.g.
* LayerTypeInfo.size)
*/
void (*free)(void *data, int count);
cd_free free;
/**
* a function to interpolate between count source elements of this
@ -165,7 +166,7 @@ struct LayerTypeInfo {
* Set values to the type's default. If undefined, the default is assumed to be zeroes.
* Memory pointed to by #data is expected to be uninitialized.
*/
void (*set_default_value)(void *data, int count);
cd_set_default_value set_default_value;
/**
* Construct and fill a valid value for the type. Necessary for non-trivial types.
* Memory pointed to by #data is expected to be uninitialized.
@ -3668,6 +3669,8 @@ bool CustomData_bmesh_merge_layout(const CustomData *source,
return false;
}
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(destold, *dest);
int iter_type;
int totelem;
switch (htype) {
@ -3703,7 +3706,7 @@ bool CustomData_bmesh_merge_layout(const CustomData *source,
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (h, &iter, bm, iter_type) {
void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
CustomData_bmesh_copy_block(*dest, map, h->data, &tmp);
CustomData_bmesh_free_block(&destold, &h->data);
h->data = tmp;
}
@ -3718,7 +3721,7 @@ bool CustomData_bmesh_merge_layout(const CustomData *source,
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
CustomData_bmesh_copy_block(*dest, map, l->head.data, &tmp);
CustomData_bmesh_free_block(&destold, &l->head.data);
l->head.data = tmp;
}
@ -3835,68 +3838,76 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
}
}
static bool customdata_layer_copy_check(const CustomDataLayer &source, const CustomDataLayer &dest)
BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src,
const CustomData &dst,
const eCustomDataMask mask_exclude)
{
return source.type == dest.type && STREQ(source.name, dest.name);
}
BMCustomDataCopyMap map;
for (const CustomDataLayer &layer_dst : Span(dst.layers, dst.totlayer)) {
const int dst_offset = layer_dst.offset;
const eCustomDataType dst_type = eCustomDataType(layer_dst.type);
const LayerTypeInfo &type_info = *layerType_getInfo(dst_type);
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block,
const eCustomDataMask mask_exclude)
{
if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
memset(*dest_block, 0, dest->totsize);
}
}
BitVector<> copied_layers(dest->totlayer);
for (int layer_src_i : IndexRange(source->totlayer)) {
const CustomDataLayer &layer_src = source->layers[layer_src_i];
if (CD_TYPE_AS_MASK(layer_src.type) & mask_exclude) {
continue;
}
for (int layer_dst_i : IndexRange(dest->totlayer)) {
CustomDataLayer &layer_dst = dest->layers[layer_dst_i];
if (!customdata_layer_copy_check(layer_src, layer_dst)) {
continue;
}
copied_layers[layer_dst_i].set(true);
const void *src_data = POINTER_OFFSET(src_block, layer_src.offset);
void *dest_data = POINTER_OFFSET(*dest_block, layer_dst.offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer_src.type));
if (typeInfo->copy) {
typeInfo->copy(src_data, dest_data, 1);
const int src_offset = CustomData_get_offset_named(&src, dst_type, layer_dst.name);
if (src_offset == -1 || CD_TYPE_AS_MASK(dst_type) & mask_exclude) {
if (type_info.set_default_value) {
map.defaults.append({type_info.set_default_value, dst_offset});
}
else {
memcpy(dest_data, src_data, typeInfo->size);
map.trivial_defaults.append({type_info.size, dst_offset});
}
}
else {
if (type_info.copy) {
map.copies.append({type_info.copy, src_offset, dst_offset});
}
else {
/* NOTE: A way to improve performance of copies (by reducing the number of `memcpy`
* calls) would be combining contiguous in the source and result format. */
map.trivial_copies.append({type_info.size, src_offset, dst_offset});
}
}
}
/* Initialize dest layers that weren't in source. */
for (int layer_dst_i : IndexRange(dest->totlayer)) {
if (!copied_layers[layer_dst_i]) {
CustomData_bmesh_set_default_n(dest, dest_block, layer_dst_i);
if (type_info.free) {
map.free.append({type_info.free, dst_offset});
}
}
return map;
}
void CustomData_bmesh_copy_data(const CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block)
void CustomData_bmesh_copy_block(CustomData &dst_data,
const BMCustomDataCopyMap &copy_map,
const void *src_block,
void **dst_block)
{
CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0);
if (*dst_block) {
for (const BMCustomDataCopyMap::Free &info : copy_map.free) {
info.fn(POINTER_OFFSET(*dst_block, info.dst_offset), 1);
}
}
else {
if (dst_data.totsize == 0) {
return;
}
*dst_block = BLI_mempool_alloc(dst_data.pool);
}
for (const BMCustomDataCopyMap::TrivialCopy &info : copy_map.trivial_copies) {
memcpy(POINTER_OFFSET(*dst_block, info.dst_offset),
POINTER_OFFSET(src_block, info.src_offset),
info.size);
}
for (const BMCustomDataCopyMap::Copy &info : copy_map.copies) {
info.fn(POINTER_OFFSET(src_block, info.src_offset),
POINTER_OFFSET(*dst_block, info.dst_offset),
1);
}
for (const BMCustomDataCopyMap::TrivialDefault &info : copy_map.trivial_defaults) {
memset(POINTER_OFFSET(*dst_block, info.dst_offset), 0, info.size);
}
for (const BMCustomDataCopyMap::Default &info : copy_map.defaults) {
info.fn(POINTER_OFFSET(*dst_block, info.dst_offset), 1);
}
}
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)

View File

@ -317,149 +317,110 @@ void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
/*************************************************************/
static void bm_vert_attrs_copy(
BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, eCustomDataMask mask_exclude)
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
{
if ((bm_src == bm_dst) && (v_src == v_dst)) {
BLI_assert_msg(0, "BMVert: source and target match");
return;
}
if ((mask_exclude & CD_MASK_NORMAL) == 0) {
copy_v3_v3(v_dst->no, v_src->no);
}
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->vdata, v_dst->head.data, mask_exclude);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->vdata, &bm_dst->vdata, v_src->head.data, &v_dst->head.data, mask_exclude);
}
static void bm_edge_attrs_copy(
BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (e_src == e_dst)) {
BLI_assert_msg(0, "BMEdge: source and target match");
return;
}
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->edata, e_dst->head.data, mask_exclude);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->edata, &bm_dst->edata, e_src->head.data, &e_dst->head.data, mask_exclude);
}
static void bm_loop_attrs_copy(
BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (l_src == l_dst)) {
BLI_assert_msg(0, "BMLoop: source and target match");
return;
}
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->ldata, l_dst->head.data, mask_exclude);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->ldata, &bm_dst->ldata, l_src->head.data, &l_dst->head.data, mask_exclude);
}
static void bm_face_attrs_copy(
BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (f_src == f_dst)) {
BLI_assert_msg(0, "BMFace: source and target match");
return;
}
if ((mask_exclude & CD_MASK_NORMAL) == 0) {
copy_v3_v3(f_dst->no, f_src->no);
}
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->pdata, f_dst->head.data, mask_exclude);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->pdata, &bm_dst->pdata, f_src->head.data, &f_dst->head.data, mask_exclude);
f_dst->mat_nr = f_src->mat_nr;
}
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
void *ele_dst_v,
const char hflag_mask,
const uint64_t cd_mask_exclude)
{
/* TODO: Special handling for hide flags? */
/* TODO: swap src/dst args, everywhere else in bmesh does other way round. */
const BMHeader *ele_src = static_cast<const BMHeader *>(ele_src_v);
BMHeader *ele_dst = static_cast<BMHeader *>(ele_dst_v);
BLI_assert(ele_src->htype == ele_dst->htype);
BLI_assert(ele_src != ele_dst);
if ((hflag_mask & BM_ELEM_SELECT) == 0) {
/* First we copy select */
if (BM_elem_flag_test((BMElem *)ele_src, BM_ELEM_SELECT)) {
BM_elem_select_set(bm_dst, (BMElem *)ele_dst, true);
}
}
/* Now we copy flags */
if (hflag_mask == 0) {
ele_dst->hflag = ele_src->hflag;
}
else if (hflag_mask == 0xff) {
/* pass */
}
else {
ele_dst->hflag = ((ele_dst->hflag & hflag_mask) | (ele_src->hflag & ~hflag_mask));
}
/* Copy specific attributes */
switch (ele_dst->htype) {
case BM_VERT:
bm_vert_attrs_copy(
bm_src, bm_dst, (const BMVert *)ele_src, (BMVert *)ele_dst, cd_mask_exclude);
break;
case BM_EDGE:
bm_edge_attrs_copy(
bm_src, bm_dst, (const BMEdge *)ele_src, (BMEdge *)ele_dst, cd_mask_exclude);
break;
case BM_LOOP:
bm_loop_attrs_copy(
bm_src, bm_dst, (const BMLoop *)ele_src, (BMLoop *)ele_dst, cd_mask_exclude);
break;
case BM_FACE:
bm_face_attrs_copy(
bm_src, bm_dst, (const BMFace *)ele_src, (BMFace *)ele_dst, cd_mask_exclude);
break;
default:
BLI_assert(0);
break;
}
}
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMVert *src, BMVert *dst)
{
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->vdata, dst->head.data, 0);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->vdata, &bm_dst->vdata, src->head.data, &dst->head.data, 0);
CustomData_bmesh_copy_block(bm->vdata, map, 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(const BMesh *bm_src, BMesh *bm_dst, const BMEdge *src, BMEdge *dst)
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMEdge *src, BMEdge *dst)
{
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->edata, dst->head.data, 0);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->edata, &bm_dst->edata, src->head.data, &dst->head.data, 0);
CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data);
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
}
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMFace *src, BMFace *dst)
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMFace *src, BMFace *dst)
{
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->pdata, dst->head.data, 0);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->pdata, &bm_dst->pdata, src->head.data, &dst->head.data, 0);
CustomData_bmesh_copy_block(bm->vdata, map, 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 BMCustomDataCopyMap &map, const BMLoop *src, BMLoop *dst)
{
CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data);
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
}
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMVert *src, BMVert *dst)
{
if (bm_src == bm_dst) {
BM_elem_attrs_copy(*bm_dst, src, dst);
}
else {
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->vdata, bm_dst->vdata);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
}
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMEdge *src, BMEdge *dst)
{
if (bm_src == bm_dst) {
BM_elem_attrs_copy(*bm_dst, src, dst);
}
else {
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->edata, bm_dst->edata);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
}
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMFace *src, BMFace *dst)
{
if (bm_src == bm_dst) {
BM_elem_attrs_copy(*bm_dst, src, dst);
}
else {
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->pdata, bm_dst->pdata);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
}
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMLoop *src, BMLoop *dst)
{
CustomData_bmesh_free_block_data_exclude_by_type(&bm_dst->ldata, dst->head.data, 0);
CustomData_bmesh_copy_data_exclude_by_type(
&bm_src->ldata, &bm_dst->ldata, src->head.data, &dst->head.data, 0);
dst->head.hflag = src->head.hflag & ~BM_ELEM_SELECT;
if (bm_src == bm_dst) {
BM_elem_attrs_copy(*bm_dst, src, dst);
}
else {
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(bm_src->ldata, bm_dst->ldata);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
}
void BM_elem_attrs_copy(const BMesh *bm_src,
BMesh *bm_dst,
const eCustomDataMask exclude,
const BMVert *src,
BMVert *dst)
{
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(
bm_src->vdata, bm_dst->vdata, exclude);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
void BM_elem_attrs_copy(const BMesh *bm_src,
BMesh *bm_dst,
const eCustomDataMask exclude,
const BMEdge *src,
BMEdge *dst)
{
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(
bm_src->edata, bm_dst->edata, exclude);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
void BM_elem_attrs_copy(const BMesh *bm_src,
BMesh *bm_dst,
const eCustomDataMask exclude,
const BMFace *src,
BMFace *dst)
{
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(
bm_src->pdata, bm_dst->pdata, exclude);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
void BM_elem_attrs_copy(const BMesh *bm_src,
BMesh *bm_dst,
const eCustomDataMask exclude,
const BMLoop *src,
BMLoop *dst)
{
const BMCustomDataCopyMap map = CustomData_bmesh_copy_map_calc(
bm_src->ldata, bm_dst->ldata, exclude);
BM_elem_attrs_copy(bm_dst, map, src, dst);
}
void BM_elem_attrs_copy(BMesh &bm, const BMVert *src, BMVert *dst)
@ -503,8 +464,12 @@ void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
}
/* helper function for 'BM_mesh_copy' */
static BMFace *bm_mesh_copy_new_face(
BMesh *bm_new, BMesh *bm_old, BMVert **vtable, BMEdge **etable, BMFace *f)
static BMFace *bm_mesh_copy_new_face(BMesh *bm_new,
const BMCustomDataCopyMap &face_map,
const BMCustomDataCopyMap &loop_map,
BMVert **vtable,
BMEdge **etable,
BMFace *f)
{
BMLoop **loops = BLI_array_alloca(loops, f->len);
BMVert **verts = BLI_array_alloca(verts, f->len);
@ -532,13 +497,16 @@ static BMFace *bm_mesh_copy_new_face(
/* use totface in case adding some faces fails */
BM_elem_index_set(f_new, (bm_new->totface - 1)); /* set_inline */
BM_elem_attrs_copy_ex(bm_old, bm_new, f, f_new, 0xff, 0x0);
CustomData_bmesh_copy_block(bm_new->vdata, face_map, f->head.data, &f_new->head.data);
copy_v3_v3(f_new->no, f->no);
f_new->mat_nr = f->mat_nr;
f_new->head.hflag = f->head.hflag; /* low level! don't do this for normal api use */
j = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
do {
BM_elem_attrs_copy(bm_old, bm_new, loops[j], l_iter);
CustomData_bmesh_copy_block(bm_new->vdata, loop_map, loops[j]->head.data, &l_iter->head.data);
l_iter->head.hflag = loops[j]->head.hflag & ~BM_ELEM_SELECT;
j++;
} while ((l_iter = l_iter->next) != l_first);
@ -666,6 +634,15 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize);
const BMCustomDataCopyMap vert_map = CustomData_bmesh_copy_map_calc(bm_old->vdata,
bm_new->vdata);
const BMCustomDataCopyMap edge_map = CustomData_bmesh_copy_map_calc(bm_old->edata,
bm_new->edata);
const BMCustomDataCopyMap face_map = CustomData_bmesh_copy_map_calc(bm_old->pdata,
bm_new->pdata);
const BMCustomDataCopyMap loop_map = CustomData_bmesh_copy_map_calc(bm_old->ldata,
bm_new->ldata);
vtable = static_cast<BMVert **>(
MEM_mallocN(sizeof(BMVert *) * bm_old->totvert, "BM_mesh_copy vtable"));
etable = static_cast<BMEdge **>(
@ -676,7 +653,8 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
BM_ITER_MESH_INDEX (v, &iter, bm_old, BM_VERTS_OF_MESH, i) {
/* copy between meshes so can't use 'example' argument */
v_new = BM_vert_create(bm_new, v->co, nullptr, BM_CREATE_SKIP_CD);
BM_elem_attrs_copy_ex(bm_old, bm_new, v, v_new, 0xff, 0x0);
CustomData_bmesh_copy_block(bm_new->vdata, vert_map, v->head.data, &v_new->head.data);
copy_v3_v3(v_new->no, v->no);
v_new->head.hflag = v->head.hflag; /* low level! don't do this for normal api use */
vtable[i] = v_new;
BM_elem_index_set(v, i); /* set_inline */
@ -695,7 +673,7 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
e,
BM_CREATE_SKIP_CD);
BM_elem_attrs_copy_ex(bm_old, bm_new, e, e_new, 0xff, 0x0);
CustomData_bmesh_copy_block(bm_new->edata, vert_map, e->head.data, &e_new->head.data);
e_new->head.hflag = e->head.hflag; /* low level! don't do this for normal api use */
etable[i] = e_new;
BM_elem_index_set(e, i); /* set_inline */
@ -710,7 +688,7 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
BM_ITER_MESH_INDEX (f, &iter, bm_old, BM_FACES_OF_MESH, i) {
BM_elem_index_set(f, i); /* set_inline */
f_new = bm_mesh_copy_new_face(bm_new, bm_old, vtable, etable, f);
f_new = bm_mesh_copy_new_face(bm_new, face_map, loop_map, vtable, etable, f);
ftable[i] = f_new;

View File

@ -122,17 +122,22 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
bool create_edges);
/**
* Copies attributes, e.g. customdata, header flags, etc, from one element
* to another of the same type.
* Copy attributes between elements with a precalculated map of copy operations. This significantly
* improves performance when copying, since all the work of finding common layers doesn't have to
* be done for every element.
*/
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
void *ele_dst_v,
char hflag_mask,
uint64_t cd_mask_exclude);
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst);
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMEdge *src, BMEdge *dst);
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMFace *src, BMFace *dst);
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMLoop *src, BMLoop *dst);
/** Copy attributes between elements in two BMeshes (though they may match). */
/**
* Copy attributes between elements in two BMeshes. These functions are often called with both
* pointing to the same BMesh though, so they check for that and use a simpler copy in that case.
*
* \note For better performance when copying more than one block, use the overload with a
* #BMCustomDataCopyMap precalculated map argument.
*/
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMVert *src, BMVert *dst);
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMEdge *src, BMEdge *dst);
void BM_elem_attrs_copy(const BMesh *bm_src, BMesh *bm_dst, const BMFace *src, BMFace *dst);
@ -144,6 +149,16 @@ 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);
/** Copy attributes between two BMesh elements, excluding certain custom data types. */
void BM_elem_attrs_copy(
const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMVert *src, BMVert *dst);
void BM_elem_attrs_copy(
const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMEdge *src, BMEdge *dst);
void BM_elem_attrs_copy(
const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMFace *src, BMFace *dst);
void BM_elem_attrs_copy(
const BMesh *bm_src, BMesh *bm_dst, eCustomDataMask exclude, const BMLoop *src, BMLoop *dst);
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v);
/**

View File

@ -768,6 +768,8 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
{
const BMCustomDataCopyMap cd_map = CustomData_bmesh_copy_map_calc(*olddata, *data);
BMIter iter;
BLI_mempool *oldpool = olddata->pool;
void *block;
@ -779,8 +781,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
block = nullptr;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block);
CustomData_bmesh_copy_block(*data, cd_map, eve->head.data, &block);
CustomData_bmesh_free_block(olddata, &eve->head.data);
eve->head.data = block;
}
@ -792,8 +793,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
block = nullptr;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
CustomData_bmesh_copy_block(*data, cd_map, eed->head.data, &block);
CustomData_bmesh_free_block(olddata, &eed->head.data);
eed->head.data = block;
}
@ -807,8 +807,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
block = nullptr;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
CustomData_bmesh_copy_block(*data, cd_map, l->head.data, &block);
CustomData_bmesh_free_block(olddata, &l->head.data);
l->head.data = block;
}
@ -821,8 +820,7 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
block = nullptr;
CustomData_bmesh_set_default(data, &block);
CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
CustomData_bmesh_copy_block(*data, cd_map, efa->head.data, &block);
CustomData_bmesh_free_block(olddata, &efa->head.data);
efa->head.data = block;
}

View File

@ -1494,7 +1494,35 @@ static PyObject *bpy_bm_elem_copy_from(BPy_BMElem *self, BPy_BMElem *value)
}
if (value->ele != self->ele) {
BM_elem_attrs_copy_ex(value->bm, self->bm, value->ele, self->ele, 0xff, CD_MASK_BM_ELEM_PYPTR);
switch (self->ele->head.htype) {
case BM_VERT:
BM_elem_attrs_copy(value->bm,
self->bm,
CD_MASK_BM_ELEM_PYPTR,
reinterpret_cast<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
break;
case BM_EDGE:
BM_elem_attrs_copy(value->bm,
HooglyBoogly marked this conversation as resolved Outdated

Prefer use a utility function for each type instead of copying each type & it's members here.

Prefer use a utility function for each type instead of copying each type & it's members here.
self->bm,
CD_MASK_BM_ELEM_PYPTR,
reinterpret_cast<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
break;
case BM_FACE:
BM_elem_attrs_copy(value->bm,
self->bm,
CD_MASK_BM_ELEM_PYPTR,
reinterpret_cast<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
break;
case BM_LOOP:
BM_elem_attrs_copy(value->bm,
self->bm,
CD_MASK_BM_ELEM_PYPTR,
reinterpret_cast<const BMVert *>(value->ele),
reinterpret_cast<BMVert *>(self->ele));
}
}
Py_RETURN_NONE;