WIP: use generic copy-on-write system to avoid unnecessary data copies #104470
@ -4,9 +4,9 @@
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "BLI_copy_on_write_user.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_user_counter.hh"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
@ -32,14 +32,12 @@ namespace blender::bke {
|
||||
* because that is not available in C code. If possible, the #AutoAnonymousAttributeID wrapper
|
||||
* should be used to avoid manual reference counting in C++ code.
|
||||
*/
|
||||
class AnonymousAttributeID {
|
||||
private:
|
||||
mutable std::atomic<int> users_ = 1;
|
||||
|
||||
class AnonymousAttributeID : public bCopyOnWriteMixin<AnonymousAttributeID> {
|
||||
protected:
|
||||
std::string name_;
|
||||
|
||||
public:
|
||||
AnonymousAttributeID();
|
||||
virtual ~AnonymousAttributeID() = default;
|
||||
|
||||
StringRefNull name() const
|
||||
@ -49,22 +47,14 @@ class AnonymousAttributeID {
|
||||
|
||||
virtual std::string user_name() const;
|
||||
|
||||
void user_add() const
|
||||
void delete_self() const
|
||||
{
|
||||
users_.fetch_add(1);
|
||||
}
|
||||
|
||||
void user_remove() const
|
||||
{
|
||||
const int new_users = users_.fetch_sub(1) - 1;
|
||||
if (new_users == 0) {
|
||||
MEM_delete(this);
|
||||
}
|
||||
MEM_delete(this);
|
||||
}
|
||||
};
|
||||
|
||||
/** Wrapper for #AnonymousAttributeID that avoids manual reference counting. */
|
||||
using AutoAnonymousAttributeID = UserCounter<const AnonymousAttributeID>;
|
||||
using AutoAnonymousAttributeID = COWUser<const AnonymousAttributeID>;
|
||||
|
||||
/**
|
||||
* A set of anonymous attribute names that is passed around in geometry nodes.
|
||||
|
@ -812,7 +812,6 @@ class CustomDataAttributes {
|
||||
|
||||
std::optional<blender::GMutableSpan> 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;
|
||||
|
@ -78,10 +78,6 @@ typedef enum eCDAllocType {
|
||||
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.
|
||||
@ -126,11 +122,6 @@ bool CustomData_has_interp(const struct CustomData *data);
|
||||
*/
|
||||
bool CustomData_bmesh_has_free(const struct CustomData *data);
|
||||
|
||||
/**
|
||||
* Checks if any of the custom-data layers is referenced.
|
||||
*/
|
||||
bool CustomData_has_referenced(const struct CustomData *data);
|
||||
|
||||
/**
|
||||
* Copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
|
||||
* another, while not overwriting anything else (e.g. flags). probably only
|
||||
@ -157,15 +148,23 @@ void CustomData_data_multiply(int type, void *data, float fac);
|
||||
void CustomData_data_add(int 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. The data layers
|
||||
* will be shared or copied depending on whether the layer uses COW.
|
||||
*/
|
||||
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_without_data(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);
|
||||
@ -177,8 +176,12 @@ void CustomData_update_typemap(struct CustomData *data);
|
||||
bool CustomData_merge(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
eCustomDataMask mask,
|
||||
eCDAllocType alloctype,
|
||||
int totelem);
|
||||
bool CustomData_merge_without_data(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
|
||||
@ -192,12 +195,12 @@ void CustomData_realloc(struct CustomData *data, int old_size, int new_size);
|
||||
* 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_without_data(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.
|
||||
@ -232,23 +235,42 @@ void CustomData_free_temporary(struct CustomData *data, int totelem);
|
||||
* backed by an external data array. the different allocation types are
|
||||
* defined above. returns the data of the layer.
|
||||
*/
|
||||
void *CustomData_add_layer(
|
||||
struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem);
|
||||
void *CustomData_add_layer(struct CustomData *data,
|
||||
eCustomDataType type,
|
||||
eCDAllocType alloctype,
|
||||
int totelem);
|
||||
const void *CustomData_add_layer_with_existing_data(struct CustomData *data,
|
||||
eCustomDataType type,
|
||||
int totelem,
|
||||
void *layer_data,
|
||||
const struct bCopyOnWrite *cow);
|
||||
|
||||
/**
|
||||
* Same as above but accepts a name.
|
||||
*/
|
||||
void *CustomData_add_layer_named(struct CustomData *data,
|
||||
int type,
|
||||
eCustomDataType type,
|
||||
eCDAllocType alloctype,
|
||||
void *layer,
|
||||
int totelem,
|
||||
const char *name);
|
||||
const void *CustomData_add_layer_named_with_existing_data(struct CustomData *data,
|
||||
eCustomDataType type,
|
||||
const char *name,
|
||||
int totelem,
|
||||
void *layer_data,
|
||||
const struct bCopyOnWrite *cow);
|
||||
void *CustomData_add_layer_anonymous(struct CustomData *data,
|
||||
int type,
|
||||
eCustomDataType type,
|
||||
eCDAllocType alloctype,
|
||||
void *layer,
|
||||
int totelem,
|
||||
const AnonymousAttributeIDHandle *anonymous_id);
|
||||
const void *CustomData_add_layer_anonymous_with_existing_data(
|
||||
struct CustomData *data,
|
||||
eCustomDataType type,
|
||||
const AnonymousAttributeIDHandle *anonymous_id,
|
||||
int totelem,
|
||||
void *layer_data,
|
||||
const struct bCopyOnWrite *cow);
|
||||
|
||||
/**
|
||||
* Frees the active or first data layer with the give type.
|
||||
@ -283,11 +305,6 @@ bool CustomData_has_layer(const struct CustomData *data, int type);
|
||||
int CustomData_number_of_layers(const struct CustomData *data, int 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
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_user_counter.hh"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
@ -40,18 +38,13 @@ class CurvesEditHints;
|
||||
class Instances;
|
||||
} // namespace blender::bke
|
||||
|
||||
class GeometryComponent;
|
||||
|
||||
/**
|
||||
* This is the base class for specialized geometry component types. A geometry component handles
|
||||
* a user count to allow avoiding duplication when it is wrapped with #UserCounter. It also handles
|
||||
* the attribute API, which generalizes storing and modifying generic information on a geometry.
|
||||
*/
|
||||
class GeometryComponent {
|
||||
class GeometryComponent : public bCopyOnWriteMixin<GeometryComponent> {
|
||||
private:
|
||||
/* The reference count has two purposes. When it becomes zero, the component is freed. When it is
|
||||
* larger than one, the component becomes immutable. */
|
||||
mutable std::atomic<int> users_ = 1;
|
||||
GeometryComponentType type_;
|
||||
|
||||
public:
|
||||
@ -77,13 +70,14 @@ class GeometryComponent {
|
||||
virtual bool owns_direct_data() const = 0;
|
||||
virtual void ensure_owns_direct_data() = 0;
|
||||
|
||||
void user_add() const;
|
||||
void user_remove() const;
|
||||
bool is_mutable() const;
|
||||
|
||||
GeometryComponentType type() const;
|
||||
|
||||
virtual bool is_empty() const;
|
||||
|
||||
void delete_self()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@ -109,7 +103,7 @@ inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryCompon
|
||||
*/
|
||||
struct GeometrySet {
|
||||
private:
|
||||
using GeometryComponentPtr = blender::UserCounter<class GeometryComponent>;
|
||||
using GeometryComponentPtr = blender::COWUser<class GeometryComponent>;
|
||||
/* Indexed by #GeometryComponentType. */
|
||||
std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
|
||||
|
||||
|
@ -991,7 +991,7 @@ BLI_INLINE int *BKE_mesh_material_indices_for_write(Mesh *mesh)
|
||||
return indices;
|
||||
}
|
||||
return (int *)CustomData_add_layer_named(
|
||||
&mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totpoly, "material_index");
|
||||
&mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, mesh->totpoly, "material_index");
|
||||
}
|
||||
|
||||
BLI_INLINE const float (*BKE_mesh_vert_positions(const Mesh *mesh))[3]
|
||||
@ -1043,7 +1043,7 @@ BLI_INLINE MDeformVert *BKE_mesh_deform_verts_for_write(Mesh *mesh)
|
||||
return dvert;
|
||||
}
|
||||
return (MDeformVert *)CustomData_add_layer(
|
||||
&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, mesh->totvert);
|
||||
&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, mesh->totvert);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -99,7 +99,7 @@ static float *dm_getVertArray(DerivedMesh *dm)
|
||||
|
||||
if (!positions) {
|
||||
positions = (float(*)[3])CustomData_add_layer_named(
|
||||
&dm->vertData, CD_PROP_FLOAT3, CD_SET_DEFAULT, nullptr, dm->getNumVerts(dm), "position");
|
||||
&dm->vertData, CD_PROP_FLOAT3, CD_SET_DEFAULT, dm->getNumVerts(dm), "position");
|
||||
CustomData_set_layer_flag(&dm->vertData, CD_PROP_FLOAT3, CD_FLAG_TEMPORARY);
|
||||
dm->copyVertArray(dm, positions);
|
||||
}
|
||||
@ -114,7 +114,7 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm)
|
||||
|
||||
if (!medge) {
|
||||
medge = (MEdge *)CustomData_add_layer(
|
||||
&dm->edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, dm->getNumEdges(dm));
|
||||
&dm->edgeData, CD_MEDGE, CD_SET_DEFAULT, dm->getNumEdges(dm));
|
||||
CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY);
|
||||
dm->copyEdgeArray(dm, medge);
|
||||
}
|
||||
@ -129,7 +129,7 @@ static MLoop *dm_getLoopArray(DerivedMesh *dm)
|
||||
|
||||
if (!mloop) {
|
||||
mloop = (MLoop *)CustomData_add_layer(
|
||||
&dm->loopData, CD_MLOOP, CD_SET_DEFAULT, nullptr, dm->getNumLoops(dm));
|
||||
&dm->loopData, CD_MLOOP, CD_SET_DEFAULT, dm->getNumLoops(dm));
|
||||
CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY);
|
||||
dm->copyLoopArray(dm, mloop);
|
||||
}
|
||||
@ -144,7 +144,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm)
|
||||
|
||||
if (!mpoly) {
|
||||
mpoly = (MPoly *)CustomData_add_layer(
|
||||
&dm->polyData, CD_MPOLY, CD_SET_DEFAULT, nullptr, dm->getNumPolys(dm));
|
||||
&dm->polyData, CD_MPOLY, CD_SET_DEFAULT, dm->getNumPolys(dm));
|
||||
CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY);
|
||||
dm->copyPolyArray(dm, mpoly);
|
||||
}
|
||||
@ -239,11 +239,16 @@ 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_without_data(
|
||||
&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts);
|
||||
CustomData_copy_without_data(
|
||||
&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges);
|
||||
CustomData_copy_without_data(
|
||||
&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces);
|
||||
CustomData_copy_without_data(
|
||||
&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops);
|
||||
CustomData_copy_without_data(
|
||||
&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys);
|
||||
|
||||
dm->type = type;
|
||||
dm->numVertData = numVerts;
|
||||
@ -505,7 +510,7 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc
|
||||
layerorco = (float(*)[3])CustomData_get_layer_for_write(&mesh->vdata, layer, mesh->totvert);
|
||||
if (!layerorco) {
|
||||
layerorco = (float(*)[3])CustomData_add_layer(
|
||||
&mesh->vdata, layer, CD_SET_DEFAULT, nullptr, mesh->totvert);
|
||||
&mesh->vdata, eCustomDataType(layer), CD_SET_DEFAULT, mesh->totvert);
|
||||
}
|
||||
|
||||
memcpy(layerorco, orco, sizeof(float[3]) * totvert);
|
||||
@ -886,11 +891,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
|
||||
((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) {
|
||||
/* calc */
|
||||
CustomData_add_layer(
|
||||
&mesh_final->vdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totvert);
|
||||
&mesh_final->vdata, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totvert);
|
||||
CustomData_add_layer(
|
||||
&mesh_final->edata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totedge);
|
||||
&mesh_final->edata, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totedge);
|
||||
CustomData_add_layer(
|
||||
&mesh_final->pdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totpoly);
|
||||
&mesh_final->pdata, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totpoly);
|
||||
|
||||
/* Not worth parallelizing this,
|
||||
* gives less than 0.1% overall speedup in best of best cases... */
|
||||
@ -929,11 +934,8 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
|
||||
/* add an origspace layer if needed */
|
||||
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
|
||||
if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
|
||||
CustomData_add_layer(&mesh_final->ldata,
|
||||
CD_ORIGSPACE_MLOOP,
|
||||
CD_SET_DEFAULT,
|
||||
nullptr,
|
||||
mesh_final->totloop);
|
||||
CustomData_add_layer(
|
||||
&mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh_final->totloop);
|
||||
mesh_init_origspace(mesh_final);
|
||||
}
|
||||
}
|
||||
@ -1380,11 +1382,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
|
||||
|
||||
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
|
||||
if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
|
||||
CustomData_add_layer(&mesh_final->ldata,
|
||||
CD_ORIGSPACE_MLOOP,
|
||||
CD_SET_DEFAULT,
|
||||
nullptr,
|
||||
mesh_final->totloop);
|
||||
CustomData_add_layer(
|
||||
&mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh_final->totloop);
|
||||
mesh_init_origspace(mesh_final);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
AnonymousAttributeID::AnonymousAttributeID() = default;
|
||||
|
||||
std::string AnonymousAttributeID::user_name() const
|
||||
{
|
||||
return this->name();
|
||||
|
@ -178,18 +178,15 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data
|
||||
{
|
||||
switch (initializer.type) {
|
||||
case AttributeInit::Type::Construct: {
|
||||
void *data = CustomData_add_layer(
|
||||
&custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num);
|
||||
void *data = CustomData_add_layer(&custom_data, data_type, CD_CONSTRUCT, domain_num);
|
||||
return data != nullptr;
|
||||
}
|
||||
case AttributeInit::Type::DefaultValue: {
|
||||
void *data = CustomData_add_layer(
|
||||
&custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num);
|
||||
void *data = CustomData_add_layer(&custom_data, data_type, CD_SET_DEFAULT, domain_num);
|
||||
return data != nullptr;
|
||||
}
|
||||
case AttributeInit::Type::VArray: {
|
||||
void *data = CustomData_add_layer(
|
||||
&custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num);
|
||||
void *data = CustomData_add_layer(&custom_data, data_type, CD_CONSTRUCT, domain_num);
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@ -198,13 +195,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<const AttributeInitMoveArray &>(initializer).data;
|
||||
void *data = CustomData_add_layer(
|
||||
&custom_data, data_type, CD_ASSIGN, source_data, domain_num);
|
||||
if (data == nullptr) {
|
||||
MEM_freeN(source_data);
|
||||
void *src_data = static_cast<const AttributeInitMoveArray &>(initializer).data;
|
||||
const void *stored_data = CustomData_add_layer_with_existing_data(
|
||||
&custom_data, data_type, domain_num, src_data, nullptr);
|
||||
if (stored_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (stored_data != src_data) {
|
||||
MEM_freeN(src_data);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -216,7 +216,6 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data
|
||||
static void *add_generic_custom_data_layer(CustomData &custom_data,
|
||||
const eCustomDataType data_type,
|
||||
const eCDAllocType alloctype,
|
||||
void *layer_data,
|
||||
const int domain_num,
|
||||
const AttributeIDRef &attribute_id)
|
||||
{
|
||||
@ -224,11 +223,30 @@ static void *add_generic_custom_data_layer(CustomData &custom_data,
|
||||
char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME];
|
||||
attribute_id.name().copy(attribute_name_c);
|
||||
return CustomData_add_layer_named(
|
||||
&custom_data, data_type, alloctype, layer_data, domain_num, attribute_name_c);
|
||||
&custom_data, data_type, alloctype, domain_num, attribute_name_c);
|
||||
}
|
||||
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
|
||||
return CustomData_add_layer_anonymous(
|
||||
&custom_data, data_type, alloctype, layer_data, domain_num, &anonymous_id);
|
||||
&custom_data, data_type, alloctype, domain_num, &anonymous_id);
|
||||
}
|
||||
|
||||
static const void *add_generic_custom_data_layer_with_existing_data(
|
||||
CustomData &custom_data,
|
||||
const eCustomDataType data_type,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const int domain_size,
|
||||
void *layer_data,
|
||||
const bCopyOnWrite *cow)
|
||||
{
|
||||
if (attribute_id.is_anonymous()) {
|
||||
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
|
||||
return CustomData_add_layer_anonymous_with_existing_data(
|
||||
&custom_data, data_type, &anonymous_id, domain_size, layer_data, cow);
|
||||
}
|
||||
char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME];
|
||||
attribute_id.name().copy(attribute_name_c);
|
||||
return CustomData_add_layer_named_with_existing_data(
|
||||
&custom_data, data_type, attribute_name_c, domain_size, layer_data, cow);
|
||||
}
|
||||
|
||||
static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,
|
||||
@ -241,17 +259,17 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr
|
||||
switch (initializer.type) {
|
||||
case AttributeInit::Type::Construct: {
|
||||
add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id);
|
||||
custom_data, data_type, CD_CONSTRUCT, domain_num, attribute_id);
|
||||
break;
|
||||
}
|
||||
case AttributeInit::Type::DefaultValue: {
|
||||
add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num, attribute_id);
|
||||
custom_data, data_type, CD_SET_DEFAULT, domain_num, attribute_id);
|
||||
break;
|
||||
}
|
||||
case AttributeInit::Type::VArray: {
|
||||
void *data = add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id);
|
||||
custom_data, data_type, CD_CONSTRUCT, domain_num, attribute_id);
|
||||
if (data != nullptr) {
|
||||
const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
|
||||
varray.materialize_to_uninitialized(varray.index_range(), data);
|
||||
@ -259,9 +277,9 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr
|
||||
break;
|
||||
}
|
||||
case AttributeInit::Type::MoveArray: {
|
||||
void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data;
|
||||
add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id);
|
||||
void *data = static_cast<const AttributeInitMoveArray &>(initializer).data;
|
||||
add_generic_custom_data_layer_with_existing_data(
|
||||
custom_data, data_type, attribute_id, domain_num, data, nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -553,7 +571,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)
|
||||
@ -633,16 +651,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id,
|
||||
const eCustomDataType data_type)
|
||||
{
|
||||
void *result = add_generic_custom_data_layer(
|
||||
data, data_type, CD_SET_DEFAULT, nullptr, size_, attribute_id);
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id,
|
||||
const eCustomDataType data_type,
|
||||
void *buffer)
|
||||
{
|
||||
void *result = add_generic_custom_data_layer(
|
||||
data, data_type, CD_ASSIGN, buffer, size_, attribute_id);
|
||||
data, data_type, CD_SET_DEFAULT, size_, attribute_id);
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
|
@ -183,9 +183,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;
|
||||
@ -208,15 +206,14 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
|
||||
* (which isn't generally the case). */
|
||||
dm->deformedOnly = 1;
|
||||
|
||||
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<float(*)[3]>(CustomData_get_layer_named_for_write(
|
||||
&dm->vertData, CD_PROP_FLOAT3, "position", mesh->totvert));
|
||||
@ -246,5 +243,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);
|
||||
}
|
||||
|
@ -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<int *>(MEM_dupallocN(src.curve_offsets));
|
||||
|
||||
|
@ -56,12 +56,8 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num)
|
||||
CustomData_reset(&this->point_data);
|
||||
CustomData_reset(&this->curve_data);
|
||||
|
||||
CustomData_add_layer_named(&this->point_data,
|
||||
CD_PROP_FLOAT3,
|
||||
CD_CONSTRUCT,
|
||||
nullptr,
|
||||
this->point_num,
|
||||
ATTR_POSITION.c_str());
|
||||
CustomData_add_layer_named(
|
||||
&this->point_data, CD_PROP_FLOAT3, CD_CONSTRUCT, this->point_num, ATTR_POSITION.c_str());
|
||||
|
||||
this->curve_offsets = (int *)MEM_malloc_arrayN(this->curve_num + 1, sizeof(int), __func__);
|
||||
#ifdef DEBUG
|
||||
@ -83,8 +79,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__);
|
||||
@ -227,8 +223,7 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
|
||||
if (data != nullptr) {
|
||||
return {data, num};
|
||||
}
|
||||
data = (T *)CustomData_add_layer_named(
|
||||
&custom_data, type, CD_SET_DEFAULT, nullptr, num, name.c_str());
|
||||
data = (T *)CustomData_add_layer_named(&custom_data, type, CD_SET_DEFAULT, num, name.c_str());
|
||||
MutableSpan<T> span = {data, num};
|
||||
if (num > 0 && span.first() != default_value) {
|
||||
span.fill(default_value);
|
||||
|
@ -101,11 +101,8 @@ void fill_points(const OffsetIndices<int> 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;
|
||||
}
|
||||
|
@ -2162,10 +2162,11 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask)
|
||||
static void customData_update_offsets(CustomData *data);
|
||||
|
||||
static CustomDataLayer *customData_add_layer__internal(CustomData *data,
|
||||
int type,
|
||||
eCDAllocType alloctype,
|
||||
void *layerdata,
|
||||
int totelem,
|
||||
const eCustomDataType type,
|
||||
const eCDAllocType alloctype,
|
||||
void *layer_data_to_assign,
|
||||
const bCopyOnWrite *cow_to_assign,
|
||||
const int totelem,
|
||||
const char *name);
|
||||
|
||||
void CustomData_update_typemap(CustomData *data)
|
||||
@ -2195,93 +2196,108 @@ 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<void *>(data), totelem, type_info.size);
|
||||
}
|
||||
MEM_freeN(const_cast<void *>(data));
|
||||
}
|
||||
|
||||
static bool customdata_merge_internal(const CustomData *source,
|
||||
CustomData *dest,
|
||||
const eCustomDataMask mask,
|
||||
const eCDAllocType 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(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;
|
||||
|
||||
int type = 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 bCopyOnWrite *cow_to_assign = nullptr;
|
||||
if (alloctype == CD_ASSIGN) {
|
||||
if (src_layer.data != nullptr) {
|
||||
if (src_layer.cow == 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->user_add();
|
||||
/* Share the layer. */
|
||||
layer_data_to_assign = src_layer.data;
|
||||
cow_to_assign = src_layer.cow;
|
||||
}
|
||||
}
|
||||
if (alloctype == CD_ASSIGN) {
|
||||
layer->data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CustomDataLayer *new_layer = customData_add_layer__internal(
|
||||
dest, type, alloctype, layer_data_to_assign, cow_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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2289,6 +2305,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, CD_ASSIGN, totelem);
|
||||
}
|
||||
|
||||
bool CustomData_merge_without_data(const CustomData *source,
|
||||
CustomData *dest,
|
||||
const eCustomDataMask mask,
|
||||
const eCDAllocType alloctype,
|
||||
const int totelem)
|
||||
{
|
||||
return customdata_merge_internal(source, dest, mask, alloctype, totelem);
|
||||
}
|
||||
|
||||
static bool attribute_stored_in_bmesh_flag(const StringRef name)
|
||||
{
|
||||
return ELEM(name,
|
||||
@ -2328,28 +2361,77 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData
|
||||
return dst;
|
||||
}
|
||||
|
||||
class CustomDataLayerCOW : public bCopyOnWrite {
|
||||
private:
|
||||
const void *data_;
|
||||
int totelem_;
|
||||
eCustomDataType type_;
|
||||
|
||||
public:
|
||||
CustomDataLayerCOW(const void *data, const int totelem, const eCustomDataType type)
|
||||
: bCopyOnWrite(1), data_(data), totelem_(totelem), type_(type)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void delete_self_with_data() override
|
||||
{
|
||||
free_layer_data(type_, data_, totelem_);
|
||||
MEM_delete(this);
|
||||
}
|
||||
};
|
||||
|
||||
static bCopyOnWrite *make_cow_for_array(const eCustomDataType type,
|
||||
const void *data,
|
||||
const int totelem)
|
||||
{
|
||||
return MEM_new<CustomDataLayerCOW>(__func__, data, totelem, type);
|
||||
}
|
||||
|
||||
static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totelem)
|
||||
{
|
||||
if (layer.data == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (layer.cow == nullptr) {
|
||||
/* Can not be shared without cow data. */
|
||||
return;
|
||||
}
|
||||
if (layer.cow->is_shared()) {
|
||||
const eCustomDataType type = eCustomDataType(layer.type);
|
||||
const void *old_data = layer.data;
|
||||
layer.data = copy_layer_data(type, old_data, totelem);
|
||||
layer.cow->remove_user_and_delete_if_last();
|
||||
layer.cow = make_cow_for_array(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(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__);
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(old_data, layer->data, std::min(old_size, new_size));
|
||||
}
|
||||
else {
|
||||
std::memcpy(layer->data, old_data, std::min(old_size_in_bytes, new_size_in_bytes));
|
||||
}
|
||||
layer->flag &= ~CD_FLAG_NOFREE;
|
||||
|
||||
void *new_layer_data = MEM_mallocN(new_size_in_bytes, __func__);
|
||||
/* Copy or relocate data to new array. */
|
||||
if (layer->cow && layer->cow->is_shared() && typeInfo->copy) {
|
||||
typeInfo->copy(layer->data, new_layer_data, std::min(old_size, new_size));
|
||||
}
|
||||
else {
|
||||
layer->data = MEM_reallocN(layer->data, new_size_in_bytes);
|
||||
memcpy(new_layer_data, layer->data, std::min(old_size_in_bytes, new_size_in_bytes));
|
||||
}
|
||||
/* Remove ownership of old array */
|
||||
if (layer->cow) {
|
||||
layer->cow->remove_user_and_delete_if_last();
|
||||
layer->cow = nullptr;
|
||||
}
|
||||
/* Take ownership of new array. */
|
||||
layer->data = new_layer_data;
|
||||
if (layer->data) {
|
||||
layer->cow = make_cow_for_array(eCustomDataType(layer->type), layer->data, new_size);
|
||||
}
|
||||
|
||||
if (new_size > old_size) {
|
||||
@ -2362,11 +2444,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);
|
||||
|
||||
@ -2374,28 +2452,39 @@ void CustomData_copy(const CustomData *source,
|
||||
dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
|
||||
}
|
||||
|
||||
CustomData_merge(source, dest, mask, alloctype, totelem);
|
||||
CustomData_merge(source, dest, mask, totelem);
|
||||
}
|
||||
|
||||
void CustomData_copy_without_data(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
eCustomDataMask mask,
|
||||
eCDAllocType alloctype,
|
||||
int totelem)
|
||||
{
|
||||
CustomData_reset(dest);
|
||||
|
||||
if (source->external) {
|
||||
dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
|
||||
}
|
||||
|
||||
CustomData_merge_without_data(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->user_remove();
|
||||
layer->anonymous_id->remove_user_and_delete_if_last();
|
||||
layer->anonymous_id = nullptr;
|
||||
}
|
||||
if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
if (typeInfo->free) {
|
||||
typeInfo->free(layer->data, totelem, typeInfo->size);
|
||||
}
|
||||
|
||||
const eCustomDataType type = eCustomDataType(layer->type);
|
||||
if (layer->cow == nullptr) {
|
||||
if (layer->data) {
|
||||
MEM_freeN(layer->data);
|
||||
free_layer_data(type, layer->data, totelem);
|
||||
}
|
||||
}
|
||||
else {
|
||||
layer->cow->remove_user_and_delete_if_last();
|
||||
}
|
||||
}
|
||||
|
||||
static void CustomData_external_free(CustomData *data)
|
||||
@ -2702,107 +2791,40 @@ void CustomData_clear_layer_flag(CustomData *data, const int type, const int fla
|
||||
}
|
||||
}
|
||||
|
||||
static bool customData_resize(CustomData *data, const int amount)
|
||||
static void customData_resize(CustomData *data, const int grow_amount)
|
||||
{
|
||||
CustomDataLayer *tmp = static_cast<CustomDataLayer *>(
|
||||
MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__));
|
||||
if (!tmp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data->maxlayer += amount;
|
||||
if (data->layers) {
|
||||
memcpy(tmp, data->layers, sizeof(*tmp) * data->totlayer);
|
||||
MEM_freeN(data->layers);
|
||||
}
|
||||
data->layers = tmp;
|
||||
|
||||
return true;
|
||||
data->layers = static_cast<CustomDataLayer *>(
|
||||
MEM_reallocN(data->layers, (data->maxlayer + grow_amount) * sizeof(CustomDataLayer)));
|
||||
data->maxlayer += grow_amount;
|
||||
}
|
||||
|
||||
static CustomDataLayer *customData_add_layer__internal(CustomData *data,
|
||||
const int type,
|
||||
const eCustomDataType type,
|
||||
const eCDAllocType alloctype,
|
||||
void *layerdata,
|
||||
void *layer_data_to_assign,
|
||||
const bCopyOnWrite *cow_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:
|
||||