WIP : Use an extra step of indirection in accessing CustomDataLayers via rna. #108319

Open
Martijn Versteegh wants to merge 3 commits from Baardaap/blender:fix_dangling_customdata_pointers into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
4 changed files with 127 additions and 39 deletions

View File

@ -2146,6 +2146,15 @@ static CustomDataLayer *customData_add_layer__internal(
int totelem,
const char *name);
static void CustomData_ensure_locator(CustomData *data)
{
if (!data->layer_locator) {
data->layer_locator = static_cast<CustomDataLayer **>(
MEM_mallocN(64 * sizeof(CustomDataLayer *), __FUNCTION__)); //!hack! hardcoded 64 just for testing
memset(data->layer_locator, 0, 64*sizeof(CustomDataLayer *));
}
}
void CustomData_update_typemap(CustomData *data)
{
int lasttype = -1;
@ -2154,12 +2163,15 @@ void CustomData_update_typemap(CustomData *data)
data->typemap[i] = -1;
}
CustomData_ensure_locator(data);
for (int i = 0; i < data->totlayer; i++) {
const eCustomDataType type = eCustomDataType(data->layers[i].type);
if (type != lasttype) {
data->typemap[type] = i;
lasttype = type;
}
data->layer_locator[data->layers[i].this_locator] = data->layers+i;
}
}
@ -2325,6 +2337,8 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData
dst.maxlayer = dst.totlayer = dst_layers.size();
memcpy(dst.layers, dst_layers.data(), dst_layers.as_span().size_in_bytes());
dst.layer_locator = nullptr;
CustomData_update_typemap(&dst);
return dst;
@ -2507,6 +2521,10 @@ void CustomData_free(CustomData *data, const int totelem)
MEM_freeN(data->layers);
}
if (data->layer_locator) {
MEM_freeN(data->layer_locator);
}
CustomData_external_free(data);
CustomData_reset(data);
}
@ -2525,6 +2543,11 @@ void CustomData_free_typemask(CustomData *data, const int totelem, eCustomDataMa
MEM_freeN(data->layers);
}
if (data->layer_locator) {
MEM_freeN(data->layer_locator);
}
CustomData_external_free(data);
CustomData_reset(data);
}
@ -2940,6 +2963,20 @@ static CustomDataLayer *customData_add_layer__internal(
new_layer.name[0] = '\0';
}
CustomData_ensure_locator(data);
new_layer.this_locator = -1;
for (int i = 0; i < 64; i++) {
if (data->layer_locator[i] == nullptr) {
data->layer_locator[i] = &data->layers[index];
new_layer.this_locator = i;
break;
}
}
/* In this proof-of-concept we can't handle more than 64 layers */
BLI_assert(new_layer.this_locator >=0);
if (index > 0 && data->layers[index - 1].type == type) {
new_layer.active = data->layers[index - 1].active;
new_layer.active_rnd = data->layers[index - 1].active_rnd;
@ -3083,6 +3120,7 @@ bool CustomData_free_layer(CustomData *data,
}
BLI_assert(data->layers[index].type == type);
data->layer_locator[data->layers[index].this_locator] = nullptr;
customData_free_layer__internal(&data->layers[index], totelem);
for (int i = index + 1; i < data->totlayer; i++) {
@ -3216,6 +3254,7 @@ void CustomData_free_temporary(CustomData *data, const int totelem)
}
if ((layer->flag & CD_FLAG_TEMPORARY) == CD_FLAG_TEMPORARY) {
data->layer_locator[layer->this_locator] = nullptr;
customData_free_layer__internal(layer, totelem);
changed = true;
}

View File

@ -60,6 +60,14 @@ typedef struct CustomDataLayer {
* other geometries).
*/
const ImplicitSharingInfoHandle *sharing_info;
/**
* Run-time index into the layer_locator array of the owning CustomData
* this array is used by PointerRNA to have a permanent address to
* find CustomDataLayer, while the CustomDataLayer itself gets moved around
* when layers are added and deleted.
*/
int this_locator;
char _pad2[4];
} CustomDataLayer;
#define MAX_CUSTOMDATA_LAYER_NAME 68
@ -84,6 +92,12 @@ typedef struct CustomData {
* Correct size is ensured in CustomData_update_typemap assert().
*/
int typemap[52];
/**
* runtime only! - the indices are updated together with the typemap
* the same location in the array will always point to the same layer
* as long as it exists
*/
CustomDataLayer **layer_locator;
char _pad[4];
/** Number of layers, size of layers array. */
int totlayer, maxlayer;

View File

@ -154,7 +154,7 @@ static void rna_MeshEdgeLayer_name_set(PointerRNA *ptr, const char *value)
# endif
static void rna_MeshPolyLayer_name_set(PointerRNA *ptr, const char *value)
{
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
CustomDataLayer *layer = *(CustomDataLayer **)ptr->data;
if (CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL) {
BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
@ -163,6 +163,22 @@ static void rna_MeshPolyLayer_name_set(PointerRNA *ptr, const char *value)
rna_cd_layer_name_set(rna_mesh_pdata(ptr), layer, value);
}
}
static void rna_MeshLoopLayer_name_get(PointerRNA *ptr, char *value)
{
CustomDataLayer *layer = *(CustomDataLayer **)ptr->data;
strcpy(value, layer->name); //! add checks
}
static int rna_MeshLoopLayer_name_length(PointerRNA *ptr)
{
CustomDataLayer *layer = *(CustomDataLayer **)ptr->data;
return layer->name ? strlen(layer->name) : 0;
}
static void rna_MeshLoopLayer_name_set(PointerRNA *ptr, const char *value)
{
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
@ -977,7 +993,7 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(
static char *rna_MeshUVLoopLayer_path(const PointerRNA *ptr)
{
const CustomDataLayer *cdl = ptr->data;
const CustomDataLayer *cdl = *(CustomDataLayer **)(ptr->data);
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("uv_layers[\"%s\"]", name_esc);
@ -986,7 +1002,7 @@ static char *rna_MeshUVLoopLayer_path(const PointerRNA *ptr)
static void rna_MeshUVLoopLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *mesh = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
CustomDataLayer *layer = *(CustomDataLayer **)(ptr->data);
rna_iterator_array_begin(
iter, layer->data, sizeof(float[2]), (mesh->edit_mesh) ? 0 : mesh->totloop, 0, NULL);
}
@ -1017,7 +1033,7 @@ static void bool_layer_begin(CollectionPropertyIterator *iter,
{
char bool_layer_name[MAX_CUSTOMDATA_LAYER_NAME];
Mesh *mesh = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
CustomDataLayer *layer = *(CustomDataLayer **)(ptr->data);
layername_func(layer->name, bool_layer_name);
rna_iterator_array_begin(iter,
@ -1038,7 +1054,7 @@ static int bool_layer_lookup_int(PointerRNA *ptr,
if (mesh->edit_mesh || index < 0 || index >= mesh->totloop) {
return 0;
}
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
CustomDataLayer *layer = *(CustomDataLayer **)(ptr->data);
layername_func(layer->name, bool_layer_name);
r_ptr->owner_id = &mesh->id;
@ -1089,7 +1105,7 @@ static int rna_MeshUVLoopLayer_pin_lookup_int(PointerRNA *ptr, int index, Pointe
static void rna_MeshUVLoopLayer_uv_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
CustomDataLayer *layer = *(CustomDataLayer **)(ptr->data);
rna_iterator_array_begin(
iter, layer->data, sizeof(float[2]), (me->edit_mesh) ? 0 : me->totloop, 0, NULL);
@ -1101,7 +1117,7 @@ int rna_MeshUVLoopLayer_uv_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_
if (mesh->edit_mesh || index < 0 || index >= mesh->totloop) {
return 0;
}
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
CustomDataLayer *layer = *(CustomDataLayer **)(ptr->data);
r_ptr->owner_id = &mesh->id;
r_ptr->type = &RNA_Float2AttributeValue;
@ -2122,17 +2138,17 @@ static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me,
cdl = &ldata->layers[CustomData_get_layer_index_n(ldata, CD_PROP_FLOAT2, index)];
}
RNA_pointer_create(&me->id, &RNA_MeshUVLoopLayer, cdl, &ptr);
RNA_pointer_create(&me->id, &RNA_MeshUVLoopLayer, ldata->layer_locator[cdl->this_locator], &ptr);
return ptr;
}
static void rna_Mesh_uv_layers_remove(struct Mesh *me, ReportList *reports, CustomDataLayer *layer)
static void rna_Mesh_uv_layers_remove(struct Mesh *me, ReportList *reports, CustomDataLayer **layer)
{
if (!BKE_id_attribute_find(&me->id, layer->name, CD_PROP_FLOAT2, ATTR_DOMAIN_CORNER)) {
BKE_reportf(reports, RPT_ERROR, "UV map '%s' not found", layer->name);
if (!BKE_id_attribute_find(&me->id, (*layer)->name, CD_PROP_FLOAT2, ATTR_DOMAIN_CORNER)) {
BKE_reportf(reports, RPT_ERROR, "UV map '%s' not found", (*layer)->name);
return;
}
BKE_id_attribute_remove(&me->id, layer->name, reports);
BKE_id_attribute_remove(&me->id, (*layer)->name, reports);
}
static bool rna_Mesh_is_editmode_get(PointerRNA *ptr)
@ -2606,7 +2622,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MeshUVLoopLayer", NULL);
RNA_def_struct_sdna(srna, "CustomDataLayer");
// RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshUVLoopLayer_path");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
@ -2628,7 +2644,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_struct_name_property(srna, prop);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshLoopLayer_name_set");
RNA_def_property_string_funcs(prop, "rna_MeshLoopLayer_name_get", "rna_MeshLoopLayer_name_length", "rna_MeshLoopLayer_name_set");
RNA_def_property_string_maxlength(prop, MAX_CUSTOMDATA_LAYER_NAME_NO_PREFIX);
RNA_def_property_ui_text(prop, "Name", "Name of UV map");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
@ -2640,14 +2656,14 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
// RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
RNA_def_property_boolean_funcs(
prop, "rna_MeshUVLoopLayer_active_render_get", "rna_MeshUVLoopLayer_active_render_set");
RNA_def_property_ui_text(prop, "Active Render", "Set the UV map as active for rendering");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "active_clone", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_clone", 0);
// RNA_def_property_boolean_sdna(prop, NULL, "active_clone", 0);
RNA_def_property_boolean_funcs(
prop, "rna_MeshUVLoopLayer_clone_get", "rna_MeshUVLoopLayer_clone_set");
RNA_def_property_ui_text(prop, "Active Clone", "Set the map as active for cloning");
@ -3034,13 +3050,13 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "layer", "MeshUVLoopLayer", "", "The newly created layer");
RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
#if 0
func = RNA_def_function(srna, "remove", "rna_Mesh_uv_layers_remove");
RNA_def_function_ui_description(func, "Remove a vertex color layer");
RNA_def_function_ui_description(func, "Remove a UV map");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "layer", "MeshUVLoopLayer", "", "The layer to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
#endif
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
RNA_def_property_pointer_funcs(
@ -3486,9 +3502,9 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "ldata.layers", "ldata.totlayer");
RNA_def_property_collection_funcs(prop,
"rna_Mesh_uv_layers_begin",
NULL,
NULL,
NULL,
"rna_Mesh_uv_layers_next",
"rna_Mesh_uv_layers_end",
"rna_Mesh_uv_layers_get",
"rna_Mesh_uv_layers_length",
NULL,
NULL,

View File

@ -10,29 +10,48 @@
/* Define the accessors for a basic CustomDataLayer collection, skipping anonymous layers */
#define DEFINE_CUSTOMDATA_LAYER_COLLECTION(collection_name, customdata_type, layer_type) \
/* check */ \
static int rna_##collection_name##_check(CollectionPropertyIterator *UNUSED(iter), void *data) \
{ \
CustomDataLayer *layer = (CustomDataLayer *)data; \
return (layer->anonymous_id != NULL || layer->type != layer_type); \
} \
/* begin */ \
static void rna_Mesh_##collection_name##s_begin(CollectionPropertyIterator *iter, \
PointerRNA *ptr) \
{ \
CustomData *data = rna_mesh_##customdata_type(ptr); \
if (data) { \
rna_iterator_array_begin(iter, \
(void *)data->layers, \
sizeof(CustomDataLayer), \
data->totlayer, \
0, \
rna_##collection_name##_check); \
} \
else { \
rna_iterator_array_begin(iter, NULL, 0, 0, 0, NULL); \
} \
iter->internal.count.item = 0; \
iter->internal.count.ptr = data; \
iter->valid = CustomData_number_of_layers(data, layer_type) > 0 ? 1 : 0; \
printf("rna_Mesh_%ss_begin() CD= %p valid = %d\n", #collection_name, data, iter->valid); \
} \
/* next */ \
static void rna_Mesh_##collection_name##s_next(CollectionPropertyIterator *iter) \
{\
CustomData *data = (CustomData *)(iter->internal.count.ptr); \
int item = iter->internal.count.item;\
int nr_layers = CustomData_number_of_layers(data, layer_type); \
while (++item < nr_layers) {\
int index = CustomData_get_layer_index_n(data, layer_type, item);\
if (data->layers[index].anonymous_id == NULL) { \
break; \
} \
} \
iter->valid = item < nr_layers; \
iter->internal.count.item = item; \
printf("rna_Mesh_%ss_next() item now %d\n", #collection_name, iter->internal.count.item);\
}\
/* get */ \
static PointerRNA rna_Mesh_##collection_name##s_get(CollectionPropertyIterator *iter) \
{ \
CustomData *data = (CustomData *)(iter->internal.count.ptr); \
if (iter->internal.count.item >= CustomData_number_of_layers(data, layer_type)) {\
printf("rna_Mesh_%ss_get() return null\n", #collection_name);\
return PointerRNA_NULL;\
}\
int index = CustomData_get_layer_index_n(data, layer_type, iter->internal.count.item); \
CustomDataLayer const *cdl = &data->layers[index]; \
printf("rna_Mesh_%ss_get() CD= %p item = %d cdl = %p locator = %p\n", #collection_name, data, iter->internal.count.item, cdl, &(data->layer_locator[cdl->this_locator]));\
return rna_pointer_inherit_refine(&iter->parent, &RNA_MeshUVLoopLayer, &(data->layer_locator[cdl->this_locator])) ;\
} \
static void rna_Mesh_##collection_name##s_end(CollectionPropertyIterator *UNUSED(iter)) \
{\
}\
/* length */ \
static int rna_Mesh_##collection_name##s_length(PointerRNA *ptr) \
{ \