diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index ac984cc5c87..6b887b8eeda 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -802,7 +802,6 @@ class CustomDataAttributes { std::optional get_for_write(const AttributeIDRef &attribute_id); bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type); - bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer); bool remove(const AttributeIDRef &attribute_id); bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const; diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index fc871c022b7..360f82cffb1 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -8,6 +8,7 @@ #pragma once +#include "BLI_implicit_sharing.h" #include "BLI_sys_types.h" #include "BLI_utildefines.h" #ifdef __cplusplus @@ -74,14 +75,8 @@ extern const CustomData_MeshMasks CD_MASK_EVERYTHING; /** Add/copy/merge allocation types. */ typedef enum eCDAllocType { - /** Use the data pointer. */ - CD_ASSIGN = 0, /** Allocate and set to default, which is usually just zeroed memory. */ CD_SET_DEFAULT = 2, - /** Use data pointers, set layer flag NOFREE. */ - CD_REFERENCE = 3, - /** Do a full copy of all layers, only allowed if source has same number of elements. */ - CD_DUPLICATE = 4, /** * Default construct new layer values. Does nothing for trivial types. This should be used * if all layer values will be set by the caller after creating the layer. @@ -158,28 +153,43 @@ void CustomData_data_multiply(eCustomDataType type, void *data, float fac); void CustomData_data_add(eCustomDataType type, void *data1, const void *data2); /** - * Initializes a CustomData object with the same layer setup as source. - * mask is a bit-field where `(mask & (1 << (layer type)))` indicates - * if a layer should be copied or not. alloctype must be one of the above. + * Initializes a CustomData object with the same layer setup as source. `mask` is a bit-field where + * `(mask & (1 << (layer type)))` indicates if a layer should be copied or not. Data layers using + * implicit-sharing will not actually be copied but will be shared between source and destination. */ void CustomData_copy(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, - eCDAllocType alloctype, int totelem); +/** + * Initializes a CustomData object with the same layers as source. The data is not copied from the + * source. Instead, the new layers are initialized using the given `alloctype`. + */ +void CustomData_copy_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); /* BMESH_TODO, not really a public function but readfile.c needs it */ void CustomData_update_typemap(struct CustomData *data); /** - * Same as the above, except that this will preserve existing layers, and only - * add the layers that were not there yet. + * Copies all layers from source to destination that don't exist there yet. */ bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, - eCDAllocType alloctype, int totelem); +/** + * Copies all layers from source to destination that don't exist there yet. The layer data is not + * copied. Instead the newly created layers are initialized using the given `alloctype`. + */ +bool CustomData_merge_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); /** * Reallocate custom data to a new element count. If the new size is larger, the new values use @@ -189,16 +199,16 @@ bool CustomData_merge(const struct CustomData *source, void CustomData_realloc(struct CustomData *data, int old_size, int new_size); /** - * BMesh version of CustomData_merge; merges the layouts of source and `dest`, + * BMesh version of CustomData_merge_layout; merges the layouts of source and `dest`, * then goes through the mesh and makes sure all the custom-data blocks are * consistent with the new layout. */ -bool CustomData_bmesh_merge(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - struct BMesh *bm, - char htype); +bool CustomData_bmesh_merge_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + struct BMesh *bm, + char htype); /** * Remove layers that aren't stored in BMesh or are stored as flags on BMesh. @@ -229,18 +239,25 @@ void CustomData_free_typemask(struct CustomData *data, int totelem, eCustomDataM void CustomData_free_temporary(struct CustomData *data, int totelem); /** - * Adds a data layer of the given type to the #CustomData object, optionally - * backed by an external data array. the different allocation types are - * defined above. returns the data of the layer. + * Adds a layer of the given type to the #CustomData object. The new layer is initialized based on + * the given alloctype. + * \return The layer data. */ void *CustomData_add_layer(struct CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem); + +/** + * Adds a layer of the given type to the #CustomData object. The new layer takes ownership of the + * passed in `layer_data`. If a #ImplicitSharingInfoHandle is passed in, its user count is + * increased. + */ const void *CustomData_add_layer_with_data(struct CustomData *data, eCustomDataType type, void *layer_data, - int totelem); + int totelem, + const ImplicitSharingInfoHandle *sharing_info); /** * Same as above but accepts a name. @@ -250,17 +267,26 @@ void *CustomData_add_layer_named(struct CustomData *data, eCDAllocType alloctype, int totelem, const char *name); + const void *CustomData_add_layer_named_with_data(struct CustomData *data, eCustomDataType type, void *layer_data, int totelem, - const char *name); + const char *name, + const ImplicitSharingInfoHandle *sharing_info); + void *CustomData_add_layer_anonymous(struct CustomData *data, eCustomDataType type, eCDAllocType alloctype, - void *layer, int totelem, const AnonymousAttributeIDHandle *anonymous_id); +const void *CustomData_add_layer_anonymous_with_data( + struct CustomData *data, + eCustomDataType type, + const AnonymousAttributeIDHandle *anonymous_id, + int totelem, + void *layer_data, + const ImplicitSharingInfoHandle *sharing_info); /** * Frees the active or first data layer with the give type. @@ -296,11 +322,6 @@ int CustomData_number_of_layers(const struct CustomData *data, eCustomDataType t int CustomData_number_of_anonymous_layers(const struct CustomData *data, eCustomDataType type); int CustomData_number_of_layers_typemask(const struct CustomData *data, eCustomDataMask mask); -/** - * Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers. - */ -void CustomData_duplicate_referenced_layers(CustomData *data, int totelem); - /** * Set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is * zero for the layer type, so only layer types specified by the mask will be copied diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index beb5a5ebcb7..082fa953015 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -207,11 +207,12 @@ void DM_from_template(DerivedMesh *dm, int numPolys) { const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); - CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); - CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); - CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); - CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); + CustomData_copy_layout(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); + CustomData_copy_layout(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); + CustomData_copy_layout( + &source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); + CustomData_copy_layout(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); + CustomData_copy_layout(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); dm->poly_offsets = static_cast(MEM_dupallocN(source->poly_offsets)); dm->type = type; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 210869fda33..55739083f1e 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -201,13 +201,16 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data return true; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast(initializer).data; - const void *data = CustomData_add_layer_with_data( - &custom_data, data_type, source_data, domain_num); - if (data == nullptr) { - MEM_freeN(source_data); + void *src_data = static_cast(initializer).data; + const void *stored_data = CustomData_add_layer_with_data( + &custom_data, data_type, src_data, domain_num, nullptr); + if (stored_data == nullptr) { return false; } + if (stored_data != src_data) { + MEM_freeN(src_data); + return true; + } return true; } } @@ -230,25 +233,26 @@ static void *add_generic_custom_data_layer(CustomData &custom_data, } const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); return CustomData_add_layer_anonymous( - &custom_data, data_type, alloctype, nullptr, domain_size, &anonymous_id); + &custom_data, data_type, alloctype, domain_size, &anonymous_id); } static const void *add_generic_custom_data_layer_with_existing_data( CustomData &custom_data, const eCustomDataType data_type, - void *layer_data, + const AttributeIDRef &attribute_id, const int domain_size, - const AttributeIDRef &attribute_id) + void *layer_data, + const ImplicitSharingInfo *sharing_info) { - if (!attribute_id.is_anonymous()) { - char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; - attribute_id.name().copy(attribute_name_c); - return CustomData_add_layer_named_with_data( - &custom_data, data_type, layer_data, domain_size, attribute_name_c); + if (attribute_id.is_anonymous()) { + const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); + return CustomData_add_layer_anonymous_with_data( + &custom_data, data_type, &anonymous_id, domain_size, layer_data, sharing_info); } - const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); - return CustomData_add_layer_anonymous( - &custom_data, data_type, CD_ASSIGN, layer_data, domain_size, &anonymous_id); + char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; + attribute_id.name().copy(attribute_name_c); + return CustomData_add_layer_named_with_data( + &custom_data, data_type, layer_data, domain_size, attribute_name_c, sharing_info); } static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, @@ -279,9 +283,9 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr break; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast(initializer).data; + void *data = static_cast(initializer).data; add_generic_custom_data_layer_with_existing_data( - custom_data, data_type, source_data, domain_num, attribute_id); + custom_data, data_type, attribute_id, domain_num, data, nullptr); break; } } @@ -571,7 +575,7 @@ CustomDataAttributes::~CustomDataAttributes() CustomDataAttributes::CustomDataAttributes(const CustomDataAttributes &other) { size_ = other.size_; - CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, size_); + CustomData_copy(&other.data, &data, CD_MASK_ALL, size_); } CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other) @@ -655,15 +659,6 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, return result != nullptr; } -bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id, - const eCustomDataType data_type, - void *buffer) -{ - const void *result = add_generic_custom_data_layer_with_existing_data( - data, data_type, buffer, size_, attribute_id); - return result != nullptr; -} - bool CustomDataAttributes::remove(const AttributeIDRef &attribute_id) { for (const int i : IndexRange(data.totlayer)) { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.cc b/source/blender/blenkernel/intern/cdderivedmesh.cc index 629aa6fba87..d6882ab2203 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.cc +++ b/source/blender/blenkernel/intern/cdderivedmesh.cc @@ -147,9 +147,7 @@ static CDDerivedMesh *cdDM_create(const char *desc) return cddm; } -static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, - eCDAllocType alloctype, - const CustomData_MeshMasks *mask) +static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, const CustomData_MeshMasks *mask) { CDDerivedMesh *cddm = cdDM_create(__func__); DerivedMesh *dm = &cddm->dm; @@ -167,15 +165,14 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, mesh->totloop, mesh->totpoly); - CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert); - CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge); + CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, mesh->totvert); + CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, mesh->totedge); CustomData_merge(&mesh->fdata, &dm->faceData, cddata_masks.fmask | CD_MASK_ORIGINDEX, - alloctype, 0 /* `mesh->totface` */); - CustomData_merge(&mesh->ldata, &dm->loopData, cddata_masks.lmask, alloctype, mesh->totloop); - CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly); + CustomData_merge(&mesh->ldata, &dm->loopData, cddata_masks.lmask, mesh->totloop); + CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, mesh->totpoly); cddm->vert_positions = static_cast(CustomData_get_layer_named_for_write( &dm->vertData, CD_PROP_FLOAT3, "position", mesh->totvert)); @@ -203,5 +200,5 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, DerivedMesh *CDDM_from_mesh(Mesh *mesh) { - return cdDM_from_mesh_ex(mesh, CD_REFERENCE, &CD_MASK_MESH); + return cdDM_from_mesh_ex(mesh, &CD_MASK_MESH); } diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 8e2c8506032..23dcf687931 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -62,7 +62,7 @@ static void curves_init_data(ID *id) new (&curves->geometry) blender::bke::CurvesGeometry(); } -static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag) +static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/) { using namespace blender; @@ -80,9 +80,8 @@ static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, con dst.point_num = src.point_num; dst.curve_num = src.curve_num; - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, alloc_type, dst.point_num); - CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, alloc_type, dst.curve_num); + CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); + CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); dst.curve_offsets = static_cast(MEM_dupallocN(src.curve_offsets)); diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index b1335711399..4222be8ce8a 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -80,8 +80,8 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) CustomData_free(&dst.curve_data, dst.curve_num); dst.point_num = src.point_num; dst.curve_num = src.curve_num; - CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, CD_DUPLICATE, dst.point_num); - CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, CD_DUPLICATE, dst.curve_num); + CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, dst.point_num); + CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, dst.curve_num); MEM_SAFE_FREE(dst.curve_offsets); dst.curve_offsets = (int *)MEM_malloc_arrayN(dst.point_num + 1, sizeof(int), __func__); diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc index 9785928cf0c..8a58699dd59 100644 --- a/source/blender/blenkernel/intern/curves_utils.cc +++ b/source/blender/blenkernel/intern/curves_utils.cc @@ -101,11 +101,8 @@ void fill_points(const OffsetIndices points_by_curve, bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves) { bke::CurvesGeometry dst_curves(0, src_curves.curves_num()); - CustomData_copy(&src_curves.curve_data, - &dst_curves.curve_data, - CD_MASK_ALL, - CD_DUPLICATE, - src_curves.curves_num()); + CustomData_copy( + &src_curves.curve_data, &dst_curves.curve_data, CD_MASK_ALL, src_curves.curves_num()); dst_curves.runtime->type_counts = src_curves.runtime->type_counts; return dst_curves; } diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index c513f5edb81..28ae7bfa145 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -59,6 +59,7 @@ #include "data_transfer_intern.h" using blender::float2; +using blender::ImplicitSharingInfo; using blender::IndexRange; using blender::Set; using blender::Span; @@ -2158,12 +2159,14 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask) static void customData_update_offsets(CustomData *data); -static CustomDataLayer *customData_add_layer__internal(CustomData *data, - eCustomDataType type, - eCDAllocType alloctype, - void *layerdata, - int totelem, - const char *name); +static CustomDataLayer *customData_add_layer__internal( + CustomData *data, + eCustomDataType type, + std::optional alloctype, + void *layer_data_to_assign, + const ImplicitSharingInfo *sharing_info_to_assign, + int totelem, + const char *name); void CustomData_update_typemap(CustomData *data) { @@ -2192,93 +2195,113 @@ static bool customdata_typemap_is_valid(const CustomData *data) } #endif -bool CustomData_merge(const CustomData *source, - CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem) +static void *copy_layer_data(const eCustomDataType type, const void *data, const int totelem) +{ + const LayerTypeInfo &type_info = *layerType_getInfo(type); + if (type_info.copy) { + void *new_data = MEM_malloc_arrayN(size_t(totelem), type_info.size, __func__); + type_info.copy(data, new_data, totelem); + return new_data; + } + return MEM_dupallocN(data); +} + +static void free_layer_data(const eCustomDataType type, const void *data, const int totelem) +{ + const LayerTypeInfo &type_info = *layerType_getInfo(type); + if (type_info.free) { + type_info.free(const_cast(data), totelem, type_info.size); + } + MEM_freeN(const_cast(data)); +} + +static bool customdata_merge_internal(const CustomData *source, + CustomData *dest, + const eCustomDataMask mask, + const std::optional alloctype, + const int totelem) { - // const LayerTypeInfo *typeInfo; - CustomDataLayer *layer, *newlayer; - int lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0; - int number = 0, maxnumber = -1; bool changed = false; + int last_type = -1; + int last_active = 0; + int last_render = 0; + int last_clone = 0; + int last_mask = 0; + int current_type_layer_count = 0; + int max_current_type_layer_count = -1; + for (int i = 0; i < source->totlayer; i++) { - layer = &source->layers[i]; - // typeInfo = layerType_getInfo(eCustomDataType(layer->type)); /* UNUSED */ + const CustomDataLayer &src_layer = source->layers[i]; + const eCustomDataType type = eCustomDataType(src_layer.type); + const int src_layer_flag = src_layer.flag; - const eCustomDataType type = eCustomDataType(layer->type); - int flag = layer->flag; - - if (type != lasttype) { - number = 0; - maxnumber = CustomData_layertype_layers_max(type); - lastactive = layer->active; - lastrender = layer->active_rnd; - lastclone = layer->active_clone; - lastmask = layer->active_mask; - lasttype = type; + if (type != last_type) { + current_type_layer_count = 0; + max_current_type_layer_count = CustomData_layertype_layers_max(type); + last_active = src_layer.active; + last_render = src_layer.active_rnd; + last_clone = src_layer.active_clone; + last_mask = src_layer.active_mask; + last_type = type; } else { - number++; + current_type_layer_count++; } - if (flag & CD_FLAG_NOCOPY) { + if (src_layer_flag & CD_FLAG_NOCOPY) { + /* Don't merge this layer because it's not supposed to leave the source data. */ continue; } if (!(mask & CD_TYPE_AS_MASK(type))) { + /* Don't merge this layer because it does not match the type mask. */ continue; } - if ((maxnumber != -1) && (number >= maxnumber)) { + if ((max_current_type_layer_count != -1) && + (current_type_layer_count >= max_current_type_layer_count)) { + /* Don't merge this layer because the maximum amount of layers of this type is reached. */ continue; } - if (CustomData_get_named_layer_index(dest, type, layer->name) != -1) { + if (CustomData_get_named_layer_index(dest, type, src_layer.name) != -1) { + /* Don't merge this layer because it exists in the destination already. */ continue; } - void *data; - switch (alloctype) { - case CD_ASSIGN: - case CD_REFERENCE: - case CD_DUPLICATE: - data = layer->data; - break; - default: - data = nullptr; - break; - } - - if ((alloctype == CD_ASSIGN) && (flag & CD_FLAG_NOFREE)) { - newlayer = customData_add_layer__internal( - dest, type, CD_REFERENCE, data, totelem, layer->name); - } - else { - newlayer = customData_add_layer__internal(dest, type, alloctype, data, totelem, layer->name); - } - - if (newlayer) { - newlayer->uid = layer->uid; - - newlayer->active = lastactive; - newlayer->active_rnd = lastrender; - newlayer->active_clone = lastclone; - newlayer->active_mask = lastmask; - newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY); - changed = true; - - if (layer->anonymous_id != nullptr) { - newlayer->anonymous_id = layer->anonymous_id; - if (alloctype == CD_ASSIGN) { - layer->anonymous_id = nullptr; + void *layer_data_to_assign = nullptr; + const ImplicitSharingInfo *sharing_info_to_assign = nullptr; + if (!alloctype.has_value()) { + if (src_layer.data != nullptr) { + if (src_layer.sharing_info == nullptr) { + /* Can't share the layer, duplicate it instead. */ + layer_data_to_assign = copy_layer_data(type, src_layer.data, totelem); } else { - layer->anonymous_id->add_user(); + /* Share the layer. */ + layer_data_to_assign = src_layer.data; + sharing_info_to_assign = src_layer.sharing_info; } } - if (alloctype == CD_ASSIGN) { - layer->data = nullptr; - } + } + + CustomDataLayer *new_layer = customData_add_layer__internal(dest, + type, + alloctype, + layer_data_to_assign, + sharing_info_to_assign, + totelem, + src_layer.name); + + new_layer->uid = src_layer.uid; + new_layer->flag |= src_layer_flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY); + new_layer->active = last_active; + new_layer->active_rnd = last_render; + new_layer->active_clone = last_clone; + new_layer->active_mask = last_mask; + changed = true; + + if (src_layer.anonymous_id != nullptr) { + new_layer->anonymous_id = src_layer.anonymous_id; + new_layer->anonymous_id->add_user(); } } @@ -2286,6 +2309,23 @@ bool CustomData_merge(const CustomData *source, return changed; } +bool CustomData_merge(const CustomData *source, + CustomData *dest, + eCustomDataMask mask, + int totelem) +{ + return customdata_merge_internal(source, dest, mask, std::nullopt, totelem); +} + +bool CustomData_merge_layout(const CustomData *source, + CustomData *dest, + const eCustomDataMask mask, + const eCDAllocType alloctype, + const int totelem) +{ + return customdata_merge_internal(source, dest, mask, alloctype, totelem); +} + CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, const eCustomDataMask mask) { @@ -2311,28 +2351,91 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData return dst; } +/** + * An #ImplicitSharingInfo that knows how to free the entire referenced custom data layer + * (including potentially separately allocated chunks like for vertex groups). + */ +class CustomDataLayerImplicitSharing : public ImplicitSharingInfo { + private: + const void *data_; + const int totelem_; + const eCustomDataType type_; + + public: + CustomDataLayerImplicitSharing(const void *data, const int totelem, const eCustomDataType type) + : ImplicitSharingInfo(1), data_(data), totelem_(totelem), type_(type) + { + } + + private: + void delete_self_with_data() override + { + free_layer_data(type_, data_, totelem_); + MEM_delete(this); + } +}; + +/** Create a #ImplicitSharingInfo that takes ownership of the data. */ +static ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type, + const void *data, + const int totelem) +{ + return MEM_new(__func__, data, totelem, type); +} + +/** + * If the layer data is currently shared (hence it is immutable), create a copy that can be edited. + */ +static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totelem) +{ + if (layer.data == nullptr) { + return; + } + if (layer.sharing_info == nullptr) { + /* Can not be shared without implicit-sharing data. */ + return; + } + if (layer.sharing_info->is_shared()) { + const eCustomDataType type = eCustomDataType(layer.type); + const void *old_data = layer.data; + /* Copy the layer before removing the user because otherwise the data might be freed while + * we're still copying from it here. */ + layer.data = copy_layer_data(type, old_data, totelem); + layer.sharing_info->remove_user_and_delete_if_last(); + layer.sharing_info = make_implicit_sharing_info_for_layer(type, layer.data, totelem); + } +} + void CustomData_realloc(CustomData *data, const int old_size, const int new_size) { BLI_assert(new_size >= 0); for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(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) { - const void *old_data = layer->data; - layer->data = MEM_malloc_arrayN(new_size, typeInfo->size, __func__); + + void *new_layer_data = MEM_mallocN(new_size_in_bytes, __func__); + /* Copy data to new array. */ + if (old_size_in_bytes) { if (typeInfo->copy) { - typeInfo->copy(old_data, layer->data, std::min(old_size, new_size)); + typeInfo->copy(layer->data, new_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)); + BLI_assert(layer->data != nullptr); + memcpy(new_layer_data, layer->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); + /* Remove ownership of old array */ + if (layer->sharing_info) { + layer->sharing_info->remove_user_and_delete_if_last(); + layer->sharing_info = nullptr; + } + /* Take ownership of new array. */ + layer->data = new_layer_data; + if (layer->data) { + layer->sharing_info = make_implicit_sharing_info_for_layer( + eCustomDataType(layer->type), layer->data, new_size); } if (new_size > old_size) { @@ -2345,11 +2448,7 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size } } -void CustomData_copy(const CustomData *source, - CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem) +void CustomData_copy(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem) { CustomData_reset(dest); @@ -2357,28 +2456,40 @@ void CustomData_copy(const CustomData *source, dest->external = static_cast(MEM_dupallocN(source->external)); } - CustomData_merge(source, dest, mask, alloctype, totelem); + CustomData_merge(source, dest, mask, totelem); +} + +void CustomData_copy_layout(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem) +{ + CustomData_reset(dest); + + if (source->external) { + dest->external = static_cast(MEM_dupallocN(source->external)); + } + + CustomData_merge_layout(source, dest, mask, alloctype, totelem); } static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem) { - const LayerTypeInfo *typeInfo; - if (layer->anonymous_id != nullptr) { layer->anonymous_id->remove_user_and_delete_if_last(); layer->anonymous_id = nullptr; } - if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) { - typeInfo = layerType_getInfo(eCustomDataType(layer->type)); - - if (typeInfo->free) { - typeInfo->free(layer->data, totelem, typeInfo->size); - } - + const eCustomDataType type = eCustomDataType(layer->type); + if (layer->sharing_info == nullptr) { if (layer->data) { - MEM_freeN(layer->data); + free_layer_data(type, layer->data, totelem); } } + else { + layer->sharing_info->remove_user_and_delete_if_last(); + layer->sharing_info = nullptr; + } } static void CustomData_external_free(CustomData *data) @@ -2738,76 +2849,26 @@ static void customData_resize(CustomData *data, const int grow_amount) data->maxlayer += grow_amount; } -static CustomDataLayer *customData_add_layer__internal(CustomData *data, - const eCustomDataType type, - const eCDAllocType alloctype, - void *layerdata, - const int totelem, - const char *name) +static CustomDataLayer *customData_add_layer__internal( + CustomData *data, + const eCustomDataType type, + const std::optional alloctype, + void *layer_data_to_assign, + const ImplicitSharingInfo *sharing_info_to_assign, + const int totelem, + const char *name) { - const LayerTypeInfo *typeInfo = layerType_getInfo(type); + const LayerTypeInfo &type_info = *layerType_getInfo(type); int flag = 0; /* Some layer types only support a single layer. */ - if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { + if (!type_info.defaultname && CustomData_has_layer(data, type)) { /* This function doesn't support dealing with existing layer data for these layer types when * the layer already exists. */ - BLI_assert(layerdata == nullptr); + BLI_assert(layer_data_to_assign == nullptr); return &data->layers[CustomData_get_layer_index(data, type)]; } - void *newlayerdata = nullptr; - switch (alloctype) { - case CD_SET_DEFAULT: - if (totelem > 0) { - if (typeInfo->set_default_value) { - newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - typeInfo->set_default_value(newlayerdata, totelem); - } - else { - newlayerdata = MEM_calloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - } - } - break; - case CD_CONSTRUCT: - if (totelem > 0) { - newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - if (typeInfo->construct) { - typeInfo->construct(newlayerdata, totelem); - } - } - break; - case CD_ASSIGN: - if (totelem > 0) { - BLI_assert(layerdata != nullptr); - newlayerdata = layerdata; - } - else { - MEM_SAFE_FREE(layerdata); - } - break; - case CD_REFERENCE: - if (totelem > 0) { - BLI_assert(layerdata != nullptr); - newlayerdata = layerdata; - flag |= CD_FLAG_NOFREE; - } - break; - case CD_DUPLICATE: - if (totelem > 0) { - newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); - if (typeInfo->copy) { - typeInfo->copy(layerdata, newlayerdata, totelem); - } - else { - BLI_assert(layerdata != nullptr); - BLI_assert(newlayerdata != nullptr); - memcpy(newlayerdata, layerdata, totelem * typeInfo->size); - } - } - break; - } - int index = data->totlayer; if (index >= data->maxlayer) { customData_resize(data, CUSTOMDATA_GROW); @@ -2815,7 +2876,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, data->totlayer++; - /* keep layers ordered by type */ + /* Keep layers ordered by type. */ for (; index > 0 && data->layers[index - 1].type > type; index--) { data->layers[index] = data->layers[index - 1]; } @@ -2827,15 +2888,57 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, * leaks into the new layer. */ memset(&new_layer, 0, sizeof(CustomDataLayer)); + if (alloctype.has_value()) { + switch (*alloctype) { + case CD_SET_DEFAULT: { + if (totelem > 0) { + if (type_info.set_default_value) { + new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type)); + type_info.set_default_value(new_layer.data, totelem); + } + else { + new_layer.data = MEM_calloc_arrayN(totelem, type_info.size, layerType_getName(type)); + } + } + break; + } + case CD_CONSTRUCT: { + if (totelem > 0) { + new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type)); + if (type_info.construct) { + type_info.construct(new_layer.data, totelem); + } + } + break; + } + } + } + else { + if (totelem == 0 && sharing_info_to_assign == nullptr) { + MEM_SAFE_FREE(layer_data_to_assign); + } + else { + new_layer.data = layer_data_to_assign; + new_layer.sharing_info = sharing_info_to_assign; + if (new_layer.sharing_info) { + new_layer.sharing_info->add_user(); + } + } + } + + if (new_layer.data != nullptr && new_layer.sharing_info == nullptr) { + /* Make layer data shareable. */ + new_layer.sharing_info = make_implicit_sharing_info_for_layer(type, new_layer.data, totelem); + } + new_layer.type = type; new_layer.flag = flag; - new_layer.data = newlayerdata; /* Set default name if none exists. Note we only call DATA_() once * we know there is a default name, to avoid overhead of locale lookups * in the depsgraph. */ - if (!name && typeInfo->defaultname) { - name = DATA_(typeInfo->defaultname); + if (!name && type_info.defaultname) { + name = DATA_(type_info.defaultname); } if (name) { @@ -2864,16 +2967,15 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, return &data->layers[index]; } -static void *customdata_add_layer(CustomData *data, - const eCustomDataType type, - eCDAllocType alloctype, - void *layerdata, - const int totelem) +void *CustomData_add_layer(CustomData *data, + const eCustomDataType type, + eCDAllocType alloctype, + const int totelem) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); CustomDataLayer *layer = customData_add_layer__internal( - data, type, alloctype, layerdata, totelem, typeInfo->defaultname); + data, type, alloctype, nullptr, nullptr, totelem, typeInfo->defaultname); CustomData_update_typemap(data); if (layer) { @@ -2883,31 +2985,16 @@ static void *customdata_add_layer(CustomData *data, return nullptr; } -void *CustomData_add_layer(CustomData *data, - const eCustomDataType type, - const eCDAllocType alloctype, - const int totelem) -{ - return customdata_add_layer(data, type, alloctype, nullptr, totelem); -} - const void *CustomData_add_layer_with_data(CustomData *data, const eCustomDataType type, void *layer_data, - const int totelem) + const int totelem, + const ImplicitSharingInfo *sharing_info) { - return customdata_add_layer(data, type, CD_ASSIGN, layer_data, totelem); -} + const LayerTypeInfo *typeInfo = layerType_getInfo(type); -static void *customdata_add_layer_named(CustomData *data, - const eCustomDataType type, - const eCDAllocType alloctype, - void *layerdata, - const int totelem, - const char *name) -{ CustomDataLayer *layer = customData_add_layer__internal( - data, type, alloctype, layerdata, totelem, name); + data, type, std::nullopt, layer_data, sharing_info, totelem, typeInfo->defaultname); CustomData_update_typemap(data); if (layer) { @@ -2923,25 +3010,42 @@ void *CustomData_add_layer_named(CustomData *data, const int totelem, const char *name) { - return customdata_add_layer_named(data, type, alloctype, nullptr, totelem, name); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, alloctype, nullptr, nullptr, totelem, name); + CustomData_update_typemap(data); + + if (layer) { + return layer->data; + } + return nullptr; } -const void *CustomData_add_layer_named_with_data( - CustomData *data, const eCustomDataType type, void *layer_data, int totelem, const char *name) +const void *CustomData_add_layer_named_with_data(CustomData *data, + eCustomDataType type, + void *layer_data, + int totelem, + const char *name, + const ImplicitSharingInfo *sharing_info) { - return customdata_add_layer_named(data, type, CD_ASSIGN, layer_data, totelem, name); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, std::nullopt, layer_data, sharing_info, totelem, name); + CustomData_update_typemap(data); + + if (layer) { + return layer->data; + } + return nullptr; } void *CustomData_add_layer_anonymous(CustomData *data, const eCustomDataType type, const eCDAllocType alloctype, - void *layerdata, const int totelem, const AnonymousAttributeIDHandle *anonymous_id) { const char *name = anonymous_id->name().c_str(); CustomDataLayer *layer = customData_add_layer__internal( - data, type, alloctype, layerdata, totelem, name); + data, type, alloctype, nullptr, nullptr, totelem, name); CustomData_update_typemap(data); if (layer == nullptr) { @@ -2953,6 +3057,27 @@ void *CustomData_add_layer_anonymous(CustomData *data, return layer->data; } +const void *CustomData_add_layer_anonymous_with_data( + CustomData *data, + const eCustomDataType type, + const AnonymousAttributeIDHandle *anonymous_id, + const int totelem, + void *layer_data, + const ImplicitSharingInfo *sharing_info) +{ + const char *name = anonymous_id->name().c_str(); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, std::nullopt, layer_data, sharing_info, totelem, name); + CustomData_update_typemap(data); + + if (layer == nullptr) { + return nullptr; + } + anonymous_id->add_user(); + layer->anonymous_id = anonymous_id; + return layer->data; +} + bool CustomData_free_layer(CustomData *data, const eCustomDataType type, const int totelem, @@ -3081,47 +3206,6 @@ int CustomData_number_of_layers_typemask(const CustomData *data, const eCustomDa return number; } -static void *customData_duplicate_referenced_layer_index(CustomData *data, - const int layer_index, - const int totelem) -{ - if (layer_index == -1) { - return nullptr; - } - - CustomDataLayer *layer = &data->layers[layer_index]; - - if (layer->flag & CD_FLAG_NOFREE) { - /* MEM_dupallocN won't work in case of complex layers, like e.g. - * CD_MDEFORMVERT, which has pointers to allocated data... - * So in case a custom copy function is defined, use it! - */ - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer->type)); - - if (typeInfo->copy) { - void *dst_data = MEM_malloc_arrayN( - size_t(totelem), typeInfo->size, "CD duplicate ref layer"); - typeInfo->copy(layer->data, dst_data, totelem); - layer->data = dst_data; - } - else { - layer->data = MEM_dupallocN(layer->data); - } - - layer->flag &= ~CD_FLAG_NOFREE; - } - - return layer->data; -} - -void CustomData_duplicate_referenced_layers(CustomData *data, const int totelem) -{ - for (int i = 0; i < data->totlayer; i++) { - CustomDataLayer *layer = &data->layers[i]; - layer->data = customData_duplicate_referenced_layer_index(data, i, totelem); - } -} - void CustomData_free_temporary(CustomData *data, const int totelem) { int i, j; @@ -3299,14 +3383,12 @@ void CustomData_copy_layer_type_data(const CustomData *source, void CustomData_free_elem(CustomData *data, const int index, const int count) { for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); + const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); - if (typeInfo->free) { - size_t offset = size_t(index) * typeInfo->size; + if (typeInfo->free) { + size_t offset = size_t(index) * typeInfo->size; - typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size); - } + typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size); } } } @@ -3476,7 +3558,12 @@ void *CustomData_get_layer_for_write(CustomData *data, const int totelem) { const int layer_index = CustomData_get_active_layer_index(data, type); - return customData_duplicate_referenced_layer_index(data, layer_index, totelem); + if (layer_index == -1) { + return nullptr; + } + CustomDataLayer &layer = data->layers[layer_index]; + ensure_layer_data_is_mutable(layer, totelem); + return layer.data; } const void *CustomData_get_layer_n(const CustomData *data, const eCustomDataType type, const int n) @@ -3485,7 +3572,6 @@ const void *CustomData_get_layer_n(const CustomData *data, const eCustomDataType if (layer_index == -1) { return nullptr; } - return data->layers[layer_index].data; } @@ -3495,7 +3581,12 @@ void *CustomData_get_layer_n_for_write(CustomData *data, const int totelem) { const int layer_index = CustomData_get_layer_index_n(data, type, n); - return customData_duplicate_referenced_layer_index(data, layer_index, totelem); + if (layer_index == -1) { + return nullptr; + } + CustomDataLayer &layer = data->layers[layer_index]; + ensure_layer_data_is_mutable(layer, totelem); + return layer.data; } const void *CustomData_get_layer_named(const CustomData *data, @@ -3506,7 +3597,6 @@ const void *CustomData_get_layer_named(const CustomData *data, if (layer_index == -1) { return nullptr; } - return data->layers[layer_index].data; } @@ -3516,7 +3606,12 @@ void *CustomData_get_layer_named_for_write(CustomData *data, const int totelem) { const int layer_index = CustomData_get_named_layer_index(data, type, name); - return customData_duplicate_referenced_layer_index(data, layer_index, totelem); + if (layer_index == -1) { + return nullptr; + } + CustomDataLayer &layer = data->layers[layer_index]; + ensure_layer_data_is_mutable(layer, totelem); + return layer.data; } int CustomData_get_offset(const CustomData *data, const eCustomDataType type) @@ -3525,7 +3620,6 @@ int CustomData_get_offset(const CustomData *data, const eCustomDataType type) if (layer_index == -1) { return -1; } - return data->layers[layer_index].offset; } @@ -3610,12 +3704,12 @@ void CustomData_bmesh_init_pool(CustomData *data, const int totelem, const char } } -bool CustomData_bmesh_merge(const CustomData *source, - CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - BMesh *bm, - const char htype) +bool CustomData_bmesh_merge_layout(const CustomData *source, + CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + BMesh *bm, + const char htype) { if (CustomData_number_of_layers_typemask(source, mask) == 0) { @@ -3629,7 +3723,7 @@ bool CustomData_bmesh_merge(const CustomData *source, destold.layers = static_cast(MEM_dupallocN(destold.layers)); } - if (CustomData_merge(source, dest, mask, alloctype, 0) == false) { + if (CustomData_merge_layout(source, dest, mask, alloctype, 0) == false) { if (destold.layers) { MEM_freeN(destold.layers); } @@ -3709,13 +3803,11 @@ void CustomData_bmesh_free_block(CustomData *data, void **block) } for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); + const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); - if (typeInfo->free) { - int offset = data->layers[i].offset; - typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size); - } + if (typeInfo->free) { + int offset = data->layers[i].offset; + typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size); } } @@ -3732,12 +3824,10 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block) return; } for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); - if (typeInfo->free) { - const size_t offset = data->layers[i].offset; - typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); - } + const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); + if (typeInfo->free) { + const size_t offset = data->layers[i].offset; + typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); } } if (data->totsize) { @@ -3770,10 +3860,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, if ((CD_TYPE_AS_MASK(data->layers[i].type) & mask_exclude) == 0) { const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); const size_t offset = data->layers[i].offset; - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - if (typeInfo->free) { - typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); - } + if (typeInfo->free) { + typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); } memset(POINTER_OFFSET(block, offset), 0, typeInfo->size); } @@ -3951,11 +4039,9 @@ bool CustomData_has_math(const CustomData *data) bool CustomData_bmesh_has_free(const CustomData *data) { for (int i = 0; i < data->totlayer; i++) { - if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); - if (typeInfo->free) { - return true; - } + const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); + if (typeInfo->free) { + return true; } } return false; @@ -3973,16 +4059,6 @@ bool CustomData_has_interp(const CustomData *data) return false; } -bool CustomData_has_referenced(const CustomData *data) -{ - for (int i = 0; i < data->totlayer; i++) { - if (data->layers[i].flag & CD_FLAG_NOFREE) { - return true; - } - } - return false; -} - void CustomData_data_copy_value(const eCustomDataType type, const void *source, void *dest) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -5188,11 +5264,15 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int if (layer->flag & CD_FLAG_EXTERNAL) { layer->flag &= ~CD_FLAG_IN_MEMORY; } - - layer->flag &= ~CD_FLAG_NOFREE; + layer->sharing_info = nullptr; if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); + if (layer->data != nullptr) { + /* Make layer data shareable. */ + layer->sharing_info = make_implicit_sharing_info_for_layer( + eCustomDataType(layer->type), layer->data, count); + } if (CustomData_layer_ensure_data_exists(layer, count)) { /* Under normal operations, this shouldn't happen, but... * For a CD_PROP_BOOL example, see #84935. diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 780064623a6..b1ed15eb31b 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -150,14 +150,13 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int mesh_dst->default_color_attribute = static_cast( MEM_dupallocN(mesh_src->default_color_attribute)); - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert); - CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge); - CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, alloc_type, mesh_dst->totloop); - CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, alloc_type, mesh_dst->totpoly); + CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, mesh_dst->totvert); + CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, mesh_dst->totedge); + CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, mesh_dst->totloop); + CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, mesh_dst->totpoly); mesh_dst->poly_offset_indices = static_cast(MEM_dupallocN(mesh_src->poly_offset_indices)); if (do_tessface) { - CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, alloc_type, mesh_dst->totface); + CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, mesh_dst->totface); } else { mesh_tessface_clear_intern(mesh_dst, false); @@ -1102,12 +1101,13 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); - CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); - CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); - CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); + CustomData_copy_layout(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); + CustomData_copy_layout(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); + CustomData_copy_layout(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); + CustomData_copy_layout(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); if (do_tessface) { - CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); + CustomData_copy_layout( + &me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1384,7 +1384,7 @@ void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh) /* Orcos are stored in normalized 0..1 range by convention. */ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob); BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false); - CustomData_add_layer_with_data(&mesh->vdata, CD_ORCO, orcodata, mesh->totvert); + CustomData_add_layer_with_data(&mesh->vdata, CD_ORCO, orcodata, mesh->totvert, nullptr); } Mesh *BKE_mesh_from_object(Object *ob) diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index 93f3b6dcf60..42890c3e04b 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -656,15 +656,15 @@ static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMesh for (int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) { const Mesh *me = mim.meshes[mesh_index]; if (me->totvert) { - CustomData_merge( + CustomData_merge_layout( &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert); } if (me->totloop) { - CustomData_merge( + CustomData_merge_layout( &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop); } if (me->totpoly) { - CustomData_merge( + CustomData_merge_layout( &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, target->totpoly); } } @@ -675,7 +675,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim) for (int mesh_index = 0; mesh_index < mim.meshes.size(); ++mesh_index) { const Mesh *me = mim.meshes[mesh_index]; if (me->totedge) { - CustomData_merge( + CustomData_merge_layout( &me->edata, &target->edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge); } } diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc index 3b769e344d4..f69213c83c8 100644 --- a/source/blender/blenkernel/intern/mesh_calc_edges.cc +++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc @@ -244,7 +244,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select /* Free old CustomData and assign new one. */ CustomData_free(&mesh->edata, mesh->totedge); CustomData_reset(&mesh->edata); - CustomData_add_layer_with_data(&mesh->edata, CD_MEDGE, new_edges.data(), new_totedge); + CustomData_add_layer_with_data(&mesh->edata, CD_MEDGE, new_edges.data(), new_totedge, nullptr); mesh->totedge = new_totedge; if (select_new_edges) { diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 65a1ebafe54..343c4a7529f 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -625,7 +625,7 @@ void BKE_pointcloud_from_mesh(const Mesh *me, PointCloud *pointcloud) { CustomData_free(&pointcloud->pdata, pointcloud->totpoint); pointcloud->totpoint = me->totvert; - CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert); + CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, me->totvert); } void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob) @@ -652,8 +652,7 @@ void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/ void BKE_mesh_from_pointcloud(const PointCloud *pointcloud, Mesh *me) { me->totvert = pointcloud->totpoint; - CustomData_merge( - &pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, CD_DUPLICATE, pointcloud->totpoint); + CustomData_merge(&pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, pointcloud->totpoint); } void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob) @@ -1116,13 +1115,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) BKE_mesh_clear_geometry_and_metadata(mesh_dst); - /* Make sure referenced layers have a single user so assigning them to the mesh in main doesn't - * share them. "Referenced" layers are not expected to be shared between original meshes. */ - CustomData_duplicate_referenced_layers(&mesh_src->vdata, mesh_src->totvert); - CustomData_duplicate_referenced_layers(&mesh_src->edata, mesh_src->totedge); - CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly); - CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop); - const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert; mesh_dst->totvert = mesh_src->totvert; mesh_dst->totedge = mesh_src->totedge; @@ -1131,10 +1123,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) /* Using #CD_MASK_MESH ensures that only data that should exist in Main meshes is moved. */ const CustomData_MeshMasks mask = CD_MASK_MESH; - CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, CD_ASSIGN, mesh_src->totvert); - CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, CD_ASSIGN, mesh_src->totedge); - CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, CD_ASSIGN, mesh_src->totpoly); - CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, CD_ASSIGN, mesh_src->totloop); + CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, mesh_src->totvert); + CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, mesh_src->totedge); + CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, mesh_src->totpoly); + CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, mesh_src->totloop); std::swap(mesh_dst->poly_offset_indices, mesh_src->poly_offset_indices); /* Make sure attribute names are moved. */ diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 22b3a8d652c..8dcac9e0ae4 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -227,7 +227,7 @@ void BKE_mesh_calc_edges_legacy(Mesh *me) return; } - edges = (MEdge *)CustomData_add_layer_with_data(&me->edata, CD_MEDGE, edges, totedge); + edges = (MEdge *)CustomData_add_layer_with_data(&me->edata, CD_MEDGE, edges, totedge, nullptr); me->totedge = totedge; BKE_mesh_tag_topology_changed(me); @@ -1149,11 +1149,11 @@ static int mesh_tessface_calc(Mesh &mesh, sizeof(*mface_to_poly_map) * size_t(totface)); } - CustomData_add_layer_with_data(fdata, CD_MFACE, mface, totface); + CustomData_add_layer_with_data(fdata, CD_MFACE, mface, totface, nullptr); /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons * they are directly tessellated from. */ - CustomData_add_layer_with_data(fdata, CD_ORIGINDEX, mface_to_poly_map, totface); + CustomData_add_layer_with_data(fdata, CD_ORIGINDEX, mface_to_poly_map, totface, nullptr); add_mface_layers(mesh, fdata, ldata, totface); /* NOTE: quad detection issue - fourth vertex-index vs fourth loop-index: @@ -1297,17 +1297,28 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh) return; } void *faceset_data = nullptr; + const ImplicitSharingInfo *faceset_sharing_info = nullptr; for (const int i : IndexRange(mesh->pdata.totlayer)) { - if (mesh->pdata.layers[i].type == CD_SCULPT_FACE_SETS) { - faceset_data = mesh->pdata.layers[i].data; - mesh->pdata.layers[i].data = nullptr; + CustomDataLayer &layer = mesh->pdata.layers[i]; + if (layer.type == CD_SCULPT_FACE_SETS) { + faceset_data = layer.data; + faceset_sharing_info = layer.sharing_info; + layer.data = nullptr; + layer.sharing_info = nullptr; CustomData_free_layer(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly, i); break; } } if (faceset_data != nullptr) { - CustomData_add_layer_named_with_data( - &mesh->pdata, CD_PROP_INT32, faceset_data, mesh->totpoly, ".sculpt_face_set"); + CustomData_add_layer_named_with_data(&mesh->pdata, + CD_PROP_INT32, + faceset_data, + mesh->totpoly, + ".sculpt_face_set", + faceset_sharing_info); + } + if (faceset_sharing_info != nullptr) { + faceset_sharing_info->remove_user_and_delete_if_last(); } } @@ -1815,28 +1826,31 @@ void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh) uv_names[i] = new_name; CustomData_add_layer_named_with_data( - &mesh->ldata, CD_PROP_FLOAT2, coords, mesh->totloop, new_name); + &mesh->ldata, CD_PROP_FLOAT2, coords, mesh->totloop, new_name, nullptr); char buffer[MAX_CUSTOMDATA_LAYER_NAME]; if (vert_selection) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, vert_selection, mesh->totloop, - BKE_uv_map_vert_select_name_get(new_name, buffer)); + BKE_uv_map_vert_select_name_get(new_name, buffer), + nullptr); } if (edge_selection) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, edge_selection, mesh->totloop, - BKE_uv_map_edge_select_name_get(new_name, buffer)); + BKE_uv_map_edge_select_name_get(new_name, buffer), + nullptr); } if (pin) { CustomData_add_layer_named_with_data(&mesh->ldata, CD_PROP_BOOL, pin, mesh->totloop, - BKE_uv_map_pin_name_get(new_name, buffer)); + BKE_uv_map_pin_name_get(new_name, buffer), + nullptr); } } @@ -2272,7 +2286,8 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh) }); CustomData old_poly_data = mesh->pdata; CustomData_reset(&mesh->pdata); - CustomData_copy(&old_poly_data, &mesh->pdata, CD_MASK_MESH.pmask, CD_CONSTRUCT, mesh->totpoly); + CustomData_copy_layout( + &old_poly_data, &mesh->pdata, CD_MASK_MESH.pmask, CD_CONSTRUCT, mesh->totpoly); int offset = 0; for (const int i : orig_indices.index_range()) { diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 93457239348..c9dece1d212 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -71,18 +71,17 @@ static void pointcloud_init_data(ID *id) pointcloud->runtime = new blender::bke::PointCloudRuntime(); } -static void pointcloud_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag) +static void pointcloud_copy_data(Main * /*bmain*/, + ID *id_dst, + const ID *id_src, + const int /*flag*/) { PointCloud *pointcloud_dst = (PointCloud *)id_dst; const PointCloud *pointcloud_src = (const PointCloud *)id_src; pointcloud_dst->mat = static_cast(MEM_dupallocN(pointcloud_src->mat)); - const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; - CustomData_copy(&pointcloud_src->pdata, - &pointcloud_dst->pdata, - CD_MASK_ALL, - alloc_type, - pointcloud_dst->totpoint); + CustomData_copy( + &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, pointcloud_dst->totpoint); pointcloud_dst->runtime = new blender::bke::PointCloudRuntime(); pointcloud_dst->runtime->bounds_cache = pointcloud_src->runtime->bounds_cache; @@ -259,27 +258,12 @@ void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, { BLI_assert(pointcloud_src->id.tag & LIB_TAG_NO_MAIN); - eCDAllocType alloctype = CD_DUPLICATE; - - if (take_ownership) { - bool has_any_referenced_layers = CustomData_has_referenced(&pointcloud_src->pdata); - - if (!has_any_referenced_layers) { - alloctype = CD_ASSIGN; - } - } - CustomData_free(&pointcloud_dst->pdata, pointcloud_dst->totpoint); const int totpoint = pointcloud_dst->totpoint = pointcloud_src->totpoint; - CustomData_copy( - &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, alloctype, totpoint); + CustomData_copy(&pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, totpoint); if (take_ownership) { - if (alloctype == CD_ASSIGN) { - /* Free the CustomData but keep the layers. */ - CustomData_free_typemask(&pointcloud_src->pdata, pointcloud_src->totpoint, 0); - } BKE_id_free(nullptr, pointcloud_src); } } diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index f5c755a6930..fb686ea6d68 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -221,11 +221,11 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, else { vertex_interpolation->vertex_data = &vertex_interpolation->vertex_data_storage; /* Allocate storage for loops corresponding to ptex corners. */ - CustomData_copy(&ctx->coarse_mesh->vdata, - &vertex_interpolation->vertex_data_storage, - CD_MASK_EVERYTHING.vmask, - CD_SET_DEFAULT, - 4); + CustomData_copy_layout(&ctx->coarse_mesh->vdata, + &vertex_interpolation->vertex_data_storage, + CD_MASK_EVERYTHING.vmask, + CD_SET_DEFAULT, + 4); /* Initialize indices. */ vertex_interpolation->vertex_indices[0] = 0; vertex_interpolation->vertex_indices[1] = 1; @@ -351,11 +351,11 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, else { loop_interpolation->loop_data = &loop_interpolation->loop_data_storage; /* Allocate storage for loops corresponding to ptex corners. */ - CustomData_copy(&ctx->coarse_mesh->ldata, - &loop_interpolation->loop_data_storage, - CD_MASK_EVERYTHING.lmask, - CD_SET_DEFAULT, - 4); + CustomData_copy_layout(&ctx->coarse_mesh->ldata, + &loop_interpolation->loop_data_storage, + CD_MASK_EVERYTHING.lmask, + CD_SET_DEFAULT, + 4); /* Initialize indices. */ loop_interpolation->loop_indices[0] = 0; loop_interpolation->loop_indices[1] = 1; diff --git a/source/blender/blenlib/BLI_implicit_sharing.h b/source/blender/blenlib/BLI_implicit_sharing.h new file mode 100644 index 00000000000..37ddb005bf3 --- /dev/null +++ b/source/blender/blenlib/BLI_implicit_sharing.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + * + * This file only exists to forward declare `blender::ImplicitSharingInfo` in C code. + */ + +#ifdef __cplusplus + +namespace blender { +class ImplicitSharingInfo; +} +using ImplicitSharingInfoHandle = blender::ImplicitSharingInfo; + +#else + +typedef struct ImplicitSharingInfoHandle ImplicitSharingInfoHandle; + +#endif diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 77d71e089e1..9d80bce832e 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -243,6 +243,7 @@ set(SRC BLI_hash_tables.hh BLI_heap.h BLI_heap_simple.h + BLI_implicit_sharing.h BLI_implicit_sharing.hh BLI_implicit_sharing_ptr.hh BLI_index_mask.hh diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 609c2f526a3..562e89866d0 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -273,19 +273,19 @@ static void customdata_version_242(Mesh *me) int a, mtfacen, mcoln; if (!me->vdata.totlayer) { - CustomData_add_layer_with_data(&me->vdata, CD_MVERT, me->mvert, me->totvert); + CustomData_add_layer_with_data(&me->vdata, CD_MVERT, me->mvert, me->totvert, NULL); if (me->dvert) { - CustomData_add_layer_with_data(&me->vdata, CD_MDEFORMVERT, me->dvert, me->totvert); + CustomData_add_layer_with_data(&me->vdata, CD_MDEFORMVERT, me->dvert, me->totvert, NULL); } } if (!me->edata.totlayer) { - CustomData_add_layer_with_data(&me->edata, CD_MEDGE, me->medge, me->totedge); + CustomData_add_layer_with_data(&me->edata, CD_MEDGE, me->medge, me->totedge, NULL); } if (!me->fdata.totlayer) { - CustomData_add_layer_with_data(&me->fdata, CD_MFACE, me->mface, me->totface); + CustomData_add_layer_with_data(&me->fdata, CD_MFACE, me->mface, me->totface, NULL); if (me->tface) { if (me->mcol) { @@ -308,7 +308,7 @@ static void customdata_version_242(Mesh *me) me->tface = NULL; } else if (me->mcol) { - CustomData_add_layer_with_data(&me->fdata, CD_MCOL, me->mcol, me->totface); + CustomData_add_layer_with_data(&me->fdata, CD_MCOL, me->mcol, me->totface, NULL); } } diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 4301033189e..a62258e94ab 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -517,16 +517,16 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, &me_src->ldata, CD_MASK_BMESH.pmask); if (i == 0) { - CustomData_copy(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_merge(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_merge(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_merge(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); - CustomData_merge(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_merge_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } MEM_SAFE_FREE(mesh_vdata.layers); @@ -554,10 +554,10 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem allocsize = &bm_mesh_allocsize_default; } - CustomData_copy(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); - CustomData_copy(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 495c4537ea2..0efbfe8e9f6 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -268,10 +268,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar if (me->totvert == 0) { if (is_new) { /* No verts? still copy custom-data layout. */ - CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); - CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); - CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); - CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); + CustomData_copy_layout(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); @@ -287,16 +287,20 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } if (is_new) { - CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); - CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); + CustomData_copy_layout(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_bmesh_merge(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); - CustomData_bmesh_merge(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); - CustomData_bmesh_merge(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); - CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); + CustomData_bmesh_merge_layout( + &mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); + CustomData_bmesh_merge_layout( + &mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); + CustomData_bmesh_merge_layout( + &mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); + CustomData_bmesh_merge_layout( + &mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); } /* -------------------------------------------------------------------- */ @@ -1394,10 +1398,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh { CustomData_MeshMasks mask = CD_MASK_MESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); - CustomData_copy(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); - CustomData_copy(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); - CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); + CustomData_copy_layout(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_copy_layout(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_copy_layout(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_copy_layout(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } bool need_select_vert = false; @@ -1609,10 +1613,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * CustomData_MeshMasks_update(&mask, cd_mask_extra); } mask.vmask &= ~CD_MASK_SHAPEKEY; - CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); - CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); - CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); - CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); + CustomData_merge_layout(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); + CustomData_merge_layout(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); + CustomData_merge_layout(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); + CustomData_merge_layout(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); me->runtime->deformed_only = true; diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc index b36768d8c39..098a4ef48ee 100644 --- a/source/blender/editors/mesh/editmesh_undo.cc +++ b/source/blender/editors/mesh/editmesh_undo.cc @@ -16,6 +16,7 @@ #include "DNA_scene_types.h" #include "BLI_array_utils.h" +#include "BLI_implicit_sharing.hh" #include "BLI_listbase.h" #include "BLI_task.hh" @@ -273,8 +274,18 @@ static void um_arraystore_cd_compact(CustomData *cdata, } if (layer->data) { + if (layer->sharing_info) { + /* This assumes that the layer is not shared, which it is not here because it has just + * been created in #BM_mesh_bm_to_me. The situation is a bit tricky here, because the + * layer data may be freed partially below for e.g. vertex groups. A potentially better + * solution might be to not pass "dynamic" layers (see `layer_type_is_dynamic`) to the + * array store at all. */ + BLI_assert(layer->sharing_info->is_mutable()); + MEM_delete(layer->sharing_info); + } MEM_freeN(layer->data); layer->data = nullptr; + layer->sharing_info = nullptr; } } diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 4bc023ee10e..ce417294187 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -278,7 +278,8 @@ int ED_mesh_uv_add( CD_PROP_FLOAT2, MEM_dupallocN(CustomData_get_layer(&me->ldata, CD_PROP_FLOAT2)), me->totloop, - unique_name); + unique_name, + nullptr); is_init = true; } @@ -1143,7 +1144,7 @@ static void mesh_add_verts(Mesh *mesh, int len) int totvert = mesh->totvert + len; CustomData vdata; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); + CustomData_copy_layout(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); if (!CustomData_get_layer_named(&vdata, CD_PROP_FLOAT3, "position")) { @@ -1177,7 +1178,7 @@ static void mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_copy_layout(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { @@ -1210,7 +1211,7 @@ static void mesh_add_loops(Mesh *mesh, int len) totloop = mesh->totloop + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); + CustomData_copy_layout(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); if (!CustomData_get_layer_named(&ldata, CD_PROP_INT32, ".corner_vert")) { @@ -1247,7 +1248,7 @@ static void mesh_add_polys(Mesh *mesh, int len) totpoly = mesh->totpoly + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); + CustomData_copy_layout(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); mesh->poly_offset_indices = static_cast( diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index a9dfff00747..021d77fa152 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -105,7 +105,7 @@ static void join_mesh_single(Depsgraph *depsgraph, if (me->totvert) { /* standard data */ - CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); + CustomData_merge_layout(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert); /* vertex groups */ @@ -205,7 +205,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } if (me->totedge) { - CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_merge_layout(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge); for (a = 0; a < me->totedge; a++, edge++) { @@ -226,7 +226,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); + CustomData_merge_layout(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop); for (a = 0; a < me->totloop; a++) { @@ -250,7 +250,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); + CustomData_merge_layout(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); /* Apply matmap. In case we don't have material indices yet, create them if more than one diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index c8ae73c3013..93341a0470e 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -731,7 +731,7 @@ static void add_shapekey_layers(Mesh &mesh_dest, const Mesh &mesh_src) } CustomData_add_layer_named_with_data( - &mesh_dest.vdata, CD_SHAPEKEY, array, mesh_dest.totvert, kb->name); + &mesh_dest.vdata, CD_SHAPEKEY, array, mesh_dest.totvert, kb->name, nullptr); const int ci = CustomData_get_layer_index_n(&mesh_dest.vdata, CD_SHAPEKEY, i); mesh_dest.vdata.layers[ci].uid = kb->uid; diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc index 0833e8b7cd8..80377fd2542 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc @@ -157,14 +157,10 @@ static void SCULPT_dynamic_topology_disable_ex( me->totpoly = geometry->totpoly; me->totedge = geometry->totedge; me->totface = 0; - CustomData_copy( - &geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert); - CustomData_copy( - &geometry->edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge); - CustomData_copy( - &geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop); - CustomData_copy( - &geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly); + CustomData_copy(&geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, geometry->totvert); + CustomData_copy(&geometry->edata, &me->edata, CD_MASK_MESH.emask, geometry->totedge); + CustomData_copy(&geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, geometry->totloop); + CustomData_copy(&geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, geometry->totpoly); me->poly_offset_indices = static_cast(MEM_dupallocN(geometry->poly_offset_indices)); } else { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.cc b/source/blender/editors/sculpt_paint/sculpt_undo.cc index d267ea1e1a1..d4784c24f3a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_undo.cc @@ -745,10 +745,10 @@ static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Ob BLI_assert(!geometry->is_initialized); geometry->is_initialized = true; - CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); - CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, CD_DUPLICATE, mesh->totedge); - CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, mesh->totloop); - CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, mesh->totpoly); + CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, mesh->totvert); + CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, mesh->totedge); + CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, mesh->totloop); + CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, mesh->totpoly); geometry->poly_offset_indices = static_cast(MEM_dupallocN(mesh->poly_offset_indices)); geometry->totvert = mesh->totvert; @@ -771,14 +771,10 @@ static void sculpt_undo_geometry_restore_data(SculptUndoNodeGeometry *geometry, mesh->totpoly = geometry->totpoly; mesh->totface = 0; - CustomData_copy( - &geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert); - CustomData_copy( - &geometry->edata, &mesh->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge); - CustomData_copy( - &geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop); - CustomData_copy( - &geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly); + CustomData_copy(&geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, geometry->totvert); + CustomData_copy(&geometry->edata, &mesh->edata, CD_MASK_MESH.emask, geometry->totedge); + CustomData_copy(&geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, geometry->totloop); + CustomData_copy(&geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, geometry->totpoly); mesh->poly_offset_indices = static_cast(MEM_dupallocN(geometry->poly_offset_indices)); } diff --git a/source/blender/geometry/intern/mesh_split_edges.cc b/source/blender/geometry/intern/mesh_split_edges.cc index b1693369546..784f468ef06 100644 --- a/source/blender/geometry/intern/mesh_split_edges.cc +++ b/source/blender/geometry/intern/mesh_split_edges.cc @@ -138,7 +138,8 @@ static void add_new_edges(Mesh &mesh, mesh.edges_for_write().copy_from(new_edges); if (new_orig_indices != nullptr) { - CustomData_add_layer_with_data(&mesh.edata, CD_ORIGINDEX, new_orig_indices, mesh.totedge); + CustomData_add_layer_with_data( + &mesh.edata, CD_ORIGINDEX, new_orig_indices, mesh.totedge, nullptr); } for (NewAttributeData &new_data : dst_attributes) { diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index e0a205f9162..1efdb3926d3 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -550,7 +550,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); + CustomData_copy_layout(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 74b76f42ea8..816d39965ee 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -11,6 +11,8 @@ #include "DNA_defs.h" +#include "BLI_implicit_sharing.h" + #ifdef __cplusplus extern "C" { #endif @@ -53,6 +55,11 @@ typedef struct CustomDataLayer { * attribute was created. */ const AnonymousAttributeIDHandle *anonymous_id; + /** + * Run-time data that allows sharing `data` with other entities (mostly custom data layers on + * other geometries). + */ + const ImplicitSharingInfoHandle *sharing_info; } CustomDataLayer; #define MAX_CUSTOMDATA_LAYER_NAME 68 @@ -241,8 +248,7 @@ typedef struct CustomData_MeshMasks { enum { /* Indicates layer should not be copied by CustomData_from_template or CustomData_copy_data */ CD_FLAG_NOCOPY = (1 << 0), - /* Indicates layer should not be freed (for layers backed by external data) */ - CD_FLAG_NOFREE = (1 << 1), + CD_FLAG_UNUSED = (1 << 1), /* Indicates the layer is only temporary, also implies no copy */ CD_FLAG_TEMPORARY = ((1 << 2) | CD_FLAG_NOCOPY), /* Indicates the layer is stored in an external file */