WIP: use generic copy-on-write system to avoid unnecessary data copies #104470

Closed
Jacques Lucke wants to merge 50 commits from JacquesLucke/blender:temp-copy-on-write-customdata into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
12 changed files with 275 additions and 43 deletions
Showing only changes of commit 51388d401c - Show all commits

View File

@ -32,6 +32,9 @@ class IDPropertyDeleter {
}
};
/** \brief Allocate a new IDProperty of type IDP_BOOLEAN, set its name and value. */
std::unique_ptr<IDProperty, IDPropertyDeleter> create_bool(StringRefNull prop_name, bool value);
/** \brief Allocate a new IDProperty of type IDP_INT, set its name and value. */
std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, int32_t value);

View File

@ -21,6 +21,15 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_n
return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
}
std::unique_ptr<IDProperty, IDPropertyDeleter> create_bool(const StringRefNull prop_name,
bool value)
{
IDPropertyTemplate prop_template{0};
prop_template.i = value;
IDProperty *property = IDP_New(IDP_BOOLEAN, &prop_template, prop_name.c_str());
return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
}
std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, float value)
{
IDPropertyTemplate prop_template{0};

View File

@ -4216,7 +4216,9 @@ static int get_particle_uv(Mesh *mesh,
int i;
tf = static_cast<const MTFace *>(CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name));
if (tf == nullptr) {
tf = static_cast<const MTFace *>(CustomData_get_layer(&mesh->fdata, CD_MTFACE));
}
if (tf == nullptr) {
return 0;
}

View File

@ -62,7 +62,7 @@ static eDRWColorManagementType drw_color_management_type_for_space_image(const S
{
Image *image = sima.image;
/* Use inverse logic as there isn't a setting for `Color And Alpha`. */
/* Use inverse logic as there isn't a setting for `Color & Alpha`. */
const eSpaceImage_Flag display_channels_mode = static_cast<eSpaceImage_Flag>(sima.flag);
const bool display_color_channel = (display_channels_mode & (SI_SHOW_ALPHA | SI_SHOW_ZBUF)) == 0;

View File

@ -89,7 +89,8 @@ static void generate_strokes_actual(
lmd->silhouette_selection,
lmd->source_vertex_group,
lmd->vgname,
lmd->flags);
lmd->flags,
lmd->calculation_flags);
}
static bool isModifierDisabled(GpencilModifierData *md)

View File

@ -923,7 +923,8 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
uint8_t silhouette_mode,
const char *source_vgname,
const char *vgname,
int modifier_flags);
int modifier_flags,
int modifier_calculation_flags);
/**
* Length is in image space.

View File

@ -5156,7 +5156,8 @@ static void lineart_gpencil_generate(LineartCache *cache,
uchar silhouette_mode,
const char *source_vgname,
const char *vgname,
int modifier_flags)
int modifier_flags,
int modifier_calculation_flags)
{
if (cache == nullptr) {
if (G.debug_value == 4000) {
@ -5182,8 +5183,8 @@ static void lineart_gpencil_generate(LineartCache *cache,
/* (!orig_col && !orig_ob) means the whole scene is selected. */
int enabled_types = cache->all_enabled_edge_types;
bool invert_input = modifier_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP;
bool match_output = modifier_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP;
bool invert_input = modifier_calculation_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP;
bool match_output = modifier_calculation_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP;
bool inverse_silhouette = modifier_flags & LRT_GPENCIL_INVERT_SILHOUETTE_FILTER;
LISTBASE_FOREACH (LineartEdgeChain *, ec, &cache->chains) {
@ -5381,7 +5382,8 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
uchar silhouette_mode,
const char *source_vgname,
const char *vgname,
int modifier_flags)
int modifier_flags,
int modifier_calculation_flags)
{
if (!gpl || !gpf || !ob) {
@ -5427,5 +5429,6 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
silhouette_mode,
source_vgname,
vgname,
modifier_flags);
modifier_flags,
modifier_calculation_flags);
}

View File

@ -136,7 +136,8 @@ static bool bake_strokes(Object *ob,
lmd->silhouette_selection,
lmd->source_vertex_group,
lmd->vgname,
lmd->flags);
lmd->flags,
lmd->calculation_flags);
if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
/* Clear local cache. */

View File

@ -986,16 +986,128 @@ static char *rna_MeshUVLoopLayer_path(const PointerRNA *ptr)
static void rna_MeshUVLoopLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
Mesh *mesh = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
rna_iterator_array_begin(
iter, layer->data, sizeof(float[2]), (me->edit_mesh) ? 0 : me->totloop, 0, NULL);
iter, layer->data, sizeof(float[2]), (mesh->edit_mesh) ? 0 : mesh->totloop, 0, NULL);
}
static int rna_MeshUVLoopLayer_data_length(PointerRNA *ptr)
{
Mesh *mesh = rna_mesh(ptr);
return (mesh->edit_mesh) ? 0 : mesh->totloop;
}
static MBoolProperty *MeshUVLoopLayer_get_bool_layer(Mesh *mesh, char const *name)
{
void *layer = CustomData_get_layer_named_for_write(
&mesh->ldata, CD_PROP_BOOL, name, mesh->totloop);
if (layer == NULL) {
layer = CustomData_add_layer_named(
&mesh->ldata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totloop, name);
}
BLI_assert(layer);
return (MBoolProperty *)layer;
}
static void bool_layer_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr,
const char *(*layername_func)(const char *uv_name, char *name))
{
char bool_layer_name[MAX_CUSTOMDATA_LAYER_NAME];
Mesh *mesh = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
layername_func(layer->name, bool_layer_name);
rna_iterator_array_begin(iter,
MeshUVLoopLayer_get_bool_layer(mesh, bool_layer_name),
sizeof(MBoolProperty),
(mesh->edit_mesh) ? 0 : mesh->totloop,
0,
NULL);
}
static int bool_layer_lookup_int(PointerRNA *ptr,
int index,
PointerRNA *r_ptr,
const char *(*layername_func)(const char *uv_name, char *name))
{
char bool_layer_name[MAX_CUSTOMDATA_LAYER_NAME];
Mesh *mesh = rna_mesh(ptr);
if (mesh->edit_mesh || index < 0 || index >= mesh->totloop) {
return 0;
}
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
layername_func(layer->name, bool_layer_name);
r_ptr->owner_id = &mesh->id;
r_ptr->type = &RNA_BoolAttributeValue;
r_ptr->data = MeshUVLoopLayer_get_bool_layer(mesh, bool_layer_name) + index;
return 1;
}
/* Collection accessors for vert_select. */
static void rna_MeshUVLoopLayer_vert_select_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
bool_layer_begin(iter, ptr, BKE_uv_map_vert_select_name_get);
}
static int rna_MeshUVLoopLayer_vert_select_lookup_int(PointerRNA *ptr,
int index,
PointerRNA *r_ptr)
{
return bool_layer_lookup_int(ptr, index, r_ptr, BKE_uv_map_vert_select_name_get);
}
/* Collection accessors for edge_select. */
static void rna_MeshUVLoopLayer_edge_select_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
bool_layer_begin(iter, ptr, BKE_uv_map_edge_select_name_get);
}
static int rna_MeshUVLoopLayer_edge_select_lookup_int(PointerRNA *ptr,
int index,
PointerRNA *r_ptr)
{
return bool_layer_lookup_int(ptr, index, r_ptr, BKE_uv_map_edge_select_name_get);
}
/* Collection accessors for pin. */
static void rna_MeshUVLoopLayer_pin_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bool_layer_begin(iter, ptr, BKE_uv_map_pin_name_get);
}
static int rna_MeshUVLoopLayer_pin_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
{
return bool_layer_lookup_int(ptr, index, r_ptr, BKE_uv_map_pin_name_get);
}
static void rna_MeshUVLoopLayer_uv_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return (me->edit_mesh) ? 0 : me->totloop;
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
rna_iterator_array_begin(
iter, layer->data, sizeof(float[2]), (me->edit_mesh) ? 0 : me->totloop, 0, NULL);
}
int rna_MeshUVLoopLayer_uv_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
{
Mesh *mesh = rna_mesh(ptr);
if (mesh->edit_mesh || index < 0 || index >= mesh->totloop) {
return 0;
}
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
r_ptr->owner_id = &mesh->id;
r_ptr->type = &RNA_Float2AttributeValue;
r_ptr->data = (float *)layer->data + 2 * index;
return 1;
}
static bool rna_MeshUVLoopLayer_active_render_get(PointerRNA *ptr)
@ -2801,8 +2913,63 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Clone", "Set the map as active for cloning");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "uv", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Float2AttributeValue");
RNA_def_property_ui_text(prop, "UV", "UV coordinates on face corners");
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_uv_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_MeshUVLoopLayer_data_length",
"rna_MeshUVLoopLayer_uv_lookup_int",
NULL,
NULL);
prop = RNA_def_property(srna, "vertex_selection", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(
prop, "UV Vertex Selection", "Selection state of the face corner the UV editor");
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_vert_select_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_MeshUVLoopLayer_data_length",
"rna_MeshUVLoopLayer_vert_select_lookup_int",
NULL,
NULL);
prop = RNA_def_property(srna, "edge_selection", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(
prop, "UV Edge Selection", "Selection state of the edge in the UV editor");
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_edge_select_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_MeshUVLoopLayer_data_length",
"rna_MeshUVLoopLayer_edge_select_lookup_int",
NULL,
NULL);
prop = RNA_def_property(srna, "pin", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(prop, "UV Pin", "UV pinned state in the uv editor");
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_pin_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_MeshUVLoopLayer_data_length",
"rna_MeshUVLoopLayer_pin_lookup_int",
NULL,
NULL);
srna = RNA_def_struct(brna, "MeshUVLoop", NULL);
RNA_def_struct_ui_text(srna, "Mesh UV Layer", "Layer of UV coordinates in a Mesh data-block");
RNA_def_struct_ui_text(
srna, "Mesh UV Layer", "(Deprecated) Layer of UV coordinates in a Mesh data-block");
RNA_def_struct_path_func(srna, "rna_MeshUVLoop_path");
prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_XYZ);

View File

@ -9197,11 +9197,13 @@ static void def_cmp_denoise(StructRNA *srna)
prop = RNA_def_property(srna, "use_hdr", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "hdr", 0);
RNA_def_property_boolean_default(prop, true);
RNA_def_property_ui_text(prop, "HDR", "Process HDR images");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "prefilter", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prefilter_items);
RNA_def_property_enum_default(prop, CMP_NODE_DENOISE_PREFILTER_ACCURATE);
RNA_def_property_ui_text(prop, "", "Denoising prefilter");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}

View File

@ -371,7 +371,7 @@ static const EnumPropertyItem display_channels_items[] = {
{SI_USE_ALPHA,
"COLOR_ALPHA",
ICON_IMAGE_RGB_ALPHA,
"Color and Alpha",
"Color & Alpha",
"Display image with RGB colors and alpha transparency"},
{0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"},
{SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"},
@ -5773,7 +5773,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
{SEQ_USE_ALPHA,
"COLOR_ALPHA",
ICON_IMAGE_RGB_ALPHA,
"Color and Alpha",
"Color & Alpha",
"Display image with RGB colors and alpha transparency"},
{0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"},
{0, NULL, 0, NULL, NULL},
@ -7363,7 +7363,7 @@ static void rna_def_space_node(BlenderRNA *brna)
{SNODE_USE_ALPHA,
"COLOR_ALPHA",
ICON_IMAGE_RGB_ALPHA,
"Color and Alpha",
"Color & Alpha",
"Display image with RGB colors and alpha transparency"},
{0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"},
{SNODE_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"},

View File

@ -496,10 +496,8 @@ id_property_create_from_socket(const bNodeSocket &socket)
case SOCK_BOOLEAN: {
const bNodeSocketValueBoolean *value = static_cast<const bNodeSocketValueBoolean *>(
socket.default_value);
auto property = bke::idprop::create(socket.identifier, int(value->value));
IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get());
ui_data->min = ui_data->soft_min = 0;
ui_data->max = ui_data->soft_max = 1;
auto property = bke::idprop::create_bool(socket.identifier, value->value);
IDPropertyUIDataBool *ui_data = (IDPropertyUIDataBool *)IDP_ui_data_ensure(property.get());
ui_data->default_value = value->value != 0;
return property;
}
@ -553,7 +551,7 @@ static bool id_property_type_matches_socket(const bNodeSocket &socket, const IDP
case SOCK_RGBA:
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 4;
case SOCK_BOOLEAN:
return property.type == IDP_INT;
return property.type == IDP_BOOLEAN;
case SOCK_STRING:
return property.type == IDP_STRING;
case SOCK_OBJECT:
@ -601,7 +599,7 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
break;
}
case SOCK_BOOLEAN: {
bool value = IDP_Int(&property) != 0;
const bool value = IDP_Bool(&property);
new (r_value) ValueOrField<bool>(value);
break;
}
@ -682,16 +680,23 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
if (old_properties != nullptr) {
IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket->identifier);
if (old_prop != nullptr && id_property_type_matches_socket(*socket, *old_prop)) {
/* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
* want to replace the values). So release it temporarily and replace it after. */
IDPropertyUIData *ui_data = new_prop->ui_data;
new_prop->ui_data = nullptr;
IDP_CopyPropertyContent(new_prop, old_prop);
if (new_prop->ui_data != nullptr) {
IDP_ui_data_free(new_prop);
if (old_prop != nullptr) {
if (id_property_type_matches_socket(*socket, *old_prop)) {
/* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
* want to replace the values). So release it temporarily and replace it after. */
IDPropertyUIData *ui_data = new_prop->ui_data;
new_prop->ui_data = nullptr;
IDP_CopyPropertyContent(new_prop, old_prop);
if (new_prop->ui_data != nullptr) {
IDP_ui_data_free(new_prop);
}
new_prop->ui_data = ui_data;
}
else if (old_prop->type == IDP_INT && new_prop->type == IDP_BOOLEAN) {
/* Support versioning from integer to boolean property values. The actual value is stored
* in the same variable for both types. */
new_prop->data.val = old_prop->data.val != 0;
}
new_prop->ui_data = ui_data;
}
}
@ -1575,9 +1580,30 @@ static void add_attribute_search_or_value_buttons(const bContext &C,
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
uiLayout *name_row = uiLayoutRow(split, false);
uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
uiItemL(name_row, socket.name, ICON_NONE);
const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
if (socket.type == SOCK_BOOLEAN && !use_attribute) {
uiItemL(name_row, "", ICON_NONE);
}
else {
uiItemL(name_row, socket.name, ICON_NONE);
}
uiLayout *prop_row = uiLayoutRow(split, true);
if (socket.type == SOCK_BOOLEAN) {
uiLayoutSetPropSep(prop_row, false);
uiLayoutSetAlignment(prop_row, UI_LAYOUT_ALIGN_EXPAND);
}
if (use_attribute) {
add_attribute_search_button(C, prop_row, nmd, md_ptr, rna_path_attribute_name, socket, false);
uiItemL(layout, "", ICON_BLANK1);
}
else {
const char *name = socket.type == SOCK_BOOLEAN ? socket.name : "";
uiItemR(prop_row, md_ptr, rna_path.c_str(), 0, name, ICON_NONE);
uiItemDecoratorR(layout, md_ptr, rna_path.c_str(), -1);
}
PointerRNA props;
uiItemFullO(prop_row,
@ -1590,16 +1616,6 @@ static void add_attribute_search_or_value_buttons(const bContext &C,
&props);
RNA_string_set(&props, "modifier_name", nmd.modifier.name);
RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
if (use_attribute) {
add_attribute_search_button(C, prop_row, nmd, md_ptr, rna_path_attribute_name, socket, false);
uiItemL(layout, "", ICON_BLANK1);
}
else {
uiItemR(prop_row, md_ptr, rna_path.c_str(), 0, "", ICON_NONE);
uiItemDecoratorR(layout, md_ptr, rna_path.c_str(), -1);
}
}
/* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
@ -1665,6 +1681,9 @@ static void draw_property_for_socket(const bContext &C,
}
}
}
if (!input_has_attribute_toggle(*nmd->node_group, socket_index)) {
uiItemL(row, "", ICON_BLANK1);
}
}
static void draw_property_for_output_socket(const bContext &C,
@ -1854,9 +1873,33 @@ static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const Modif
BLO_write_struct(writer, NodesModifierData, nmd);
if (nmd->settings.properties != nullptr) {
/* Boolean properties are added automatically for boolean node group inputs. Integer properties
* are automatically converted to boolean sockets where applicable as well. However, boolean
* properties will crash old versions of Blender, so convert them to integer properties for
* writing. The actual value is stored in the same variable for both types */
Map<IDProperty *, IDPropertyUIDataBool *> boolean_props;
LISTBASE_FOREACH (IDProperty *, prop, &nmd->settings.properties->data.group) {
if (prop->type == IDP_BOOLEAN) {
boolean_props.add_new(prop, reinterpret_cast<IDPropertyUIDataBool *>(prop->ui_data));
prop->type = IDP_INT;
prop->ui_data = nullptr;
}
}
/* Note that the property settings are based on the socket type info
* and don't necessarily need to be written, but we can't just free them. */
IDP_BlendWrite(writer, nmd->settings.properties);
LISTBASE_FOREACH (IDProperty *, prop, &nmd->settings.properties->data.group) {
if (prop->type == IDP_INT) {
if (IDPropertyUIDataBool **ui_data = boolean_props.lookup_ptr(prop)) {
prop->type = IDP_BOOLEAN;
if (ui_data) {
prop->ui_data = reinterpret_cast<IDPropertyUIData *>(*ui_data);
}
}
}
}
}
}