Undo: support implicit-sharing in memfile undo step #106903

Merged
Jacques Lucke merged 78 commits from JacquesLucke/blender:implicit-sharing-undo into main 2024-02-29 17:15:09 +01:00
9 changed files with 111 additions and 75 deletions
Showing only changes of commit 11d6228ba9 - Show all commits

View File

@ -8,6 +8,7 @@
#pragma once
#include "BLI_implicit_sharing.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
#ifdef __cplusplus
@ -247,13 +248,14 @@ void *CustomData_add_layer(struct CustomData *data,
/**
* Adds a layer of the given type to the #CustomData object. The new layer takes ownership of the
* passed in `layer_data`. If a #bCopyOnWrite is passed in, it's user count is increased.
* passed in `layer_data`. If a #ImplicitSharingInfoHandle is passed in, it's user count is
* increased.
*/
const void *CustomData_add_layer_with_data(struct CustomData *data,
eCustomDataType type,
void *layer_data,
int totelem,
const struct bCopyOnWrite *cow);
const ImplicitSharingInfoHandle *implicit_sharing_info);
/**
* Same as above but accepts a name.
@ -264,12 +266,13 @@ void *CustomData_add_layer_named(struct CustomData *data,
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 struct bCopyOnWrite *cow);
const void *CustomData_add_layer_named_with_data(
struct CustomData *data,
eCustomDataType type,
void *layer_data,
int totelem,
const char *name,
const ImplicitSharingInfoHandle *implicit_sharing_info);
void *CustomData_add_layer_anonymous(struct CustomData *data,
eCustomDataType type,
@ -282,7 +285,7 @@ const void *CustomData_add_layer_anonymous_with_data(
const AnonymousAttributeIDHandle *anonymous_id,
int totelem,
void *layer_data,
const struct bCopyOnWrite *cow);
const ImplicitSharingInfoHandle *implicit_sharing_info);
/**
* Frees the active or first data layer with the give type.

View File

@ -242,17 +242,17 @@ static const void *add_generic_custom_data_layer_with_existing_data(
const AttributeIDRef &attribute_id,
const int domain_size,
void *layer_data,
const bCopyOnWrite *cow)
const ImplicitSharingInfo *implicit_sharing_info)
{
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, cow);
&custom_data, data_type, &anonymous_id, domain_size, layer_data, implicit_sharing_info);
}
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, cow);
&custom_data, data_type, layer_data, domain_size, attribute_name_c, implicit_sharing_info);
}
static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,

View File

@ -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,13 +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 *layer_data_to_assign,
const bCopyOnWrite *cow_to_assign,
int totelem,
const char *name);
static CustomDataLayer *customData_add_layer__internal(
CustomData *data,
eCustomDataType type,
eCDAllocType alloctype,
void *layer_data_to_assign,
const ImplicitSharingInfo *implicit_sharing_info_to_assign,
int totelem,
const char *name);
void CustomData_update_typemap(CustomData *data)
{
@ -2266,23 +2268,28 @@ static bool customdata_merge_internal(const CustomData *source,
}
void *layer_data_to_assign = nullptr;
const bCopyOnWrite *cow_to_assign = nullptr;
const ImplicitSharingInfo *implicit_sharing_info_to_assign = nullptr;
if (alloctype == CD_ASSIGN) {
if (src_layer.data != nullptr) {
if (src_layer.cow == nullptr) {
if (src_layer.implicit_sharing_info == nullptr) {
/* Can't share the layer, duplicate it instead. */
layer_data_to_assign = copy_layer_data(type, src_layer.data, totelem);
}
else {
/* Share the layer. */
layer_data_to_assign = src_layer.data;
cow_to_assign = src_layer.cow;
implicit_sharing_info_to_assign = src_layer.implicit_sharing_info;
}
}
}
CustomDataLayer *new_layer = customData_add_layer__internal(
dest, type, alloctype, layer_data_to_assign, cow_to_assign, totelem, src_layer.name);
CustomDataLayer *new_layer = customData_add_layer__internal(dest,
type,
alloctype,
layer_data_to_assign,
implicit_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);
@ -2345,18 +2352,18 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData
}
/**
* A #bCopyOnWrite that knows how to free the entire referenced custom data layer (including
* A #ImplicitSharingInfo that knows how to free the entire referenced custom data layer (including
* potentially separately allocated chunks like for vertex groups).
*/
class CustomDataLayerCOW : public bCopyOnWrite {
class CustomDataLayerImplicitSharing : public ImplicitSharingInfo {
private:
const void *data_;
const int totelem_;
const eCustomDataType type_;
public:
CustomDataLayerCOW(const void *data, const int totelem, const eCustomDataType type)
: bCopyOnWrite(1), data_(data), totelem_(totelem), type_(type)
CustomDataLayerImplicitSharing(const void *data, const int totelem, const eCustomDataType type)
: ImplicitSharingInfo(1), data_(data), totelem_(totelem), type_(type)
{
}
@ -2368,12 +2375,12 @@ class CustomDataLayerCOW : public bCopyOnWrite {
}
};
/** Create a #bCopyOnWrite that takes ownership of the data. */
static bCopyOnWrite *make_cow_for_array(const eCustomDataType type,
const void *data,
const int totelem)
/** Create a #ImplicitSharingInfo that takes ownership of the data. */
static ImplicitSharingInfo *make_cow_for_array(const eCustomDataType type,
const void *data,
const int totelem)
{
return MEM_new<CustomDataLayerCOW>(__func__, data, totelem, type);
return MEM_new<CustomDataLayerImplicitSharing>(__func__, data, totelem, type);
}
/**
@ -2384,16 +2391,16 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel
if (layer.data == nullptr) {
return;
}
if (layer.cow == nullptr) {
if (layer.implicit_sharing_info == nullptr) {
/* Can not be shared without cow data. */
return;
}
if (layer.cow->is_shared()) {
if (layer.implicit_sharing_info->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);
layer.implicit_sharing_info->remove_user_and_delete_if_last();
layer.implicit_sharing_info = make_cow_for_array(type, layer.data, totelem);
}
}
@ -2415,14 +2422,15 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size
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;
if (layer->implicit_sharing_info) {
layer->implicit_sharing_info->remove_user_and_delete_if_last();
layer->implicit_sharing_info = 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);
layer->implicit_sharing_info = make_cow_for_array(
eCustomDataType(layer->type), layer->data, new_size);
}
if (new_size > old_size) {
@ -2468,13 +2476,13 @@ static void customData_free_layer__internal(CustomDataLayer *layer, const int to
layer->anonymous_id = nullptr;
}
const eCustomDataType type = eCustomDataType(layer->type);
if (layer->cow == nullptr) {
if (layer->implicit_sharing_info == nullptr) {
if (layer->data) {
free_layer_data(type, layer->data, totelem);
}
}
else {
layer->cow->remove_user_and_delete_if_last();
layer->implicit_sharing_info->remove_user_and_delete_if_last();
}
}
@ -2830,13 +2838,14 @@ 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 *layer_data_to_assign,
const bCopyOnWrite *cow_to_assign,
const int totelem,
const char *name)
static CustomDataLayer *customData_add_layer__internal(
CustomData *data,
const eCustomDataType type,
const eCDAllocType alloctype,
void *layer_data_to_assign,
const ImplicitSharingInfo *implicit_sharing_info_to_assign,
const int totelem,
const char *name)
{
const LayerTypeInfo &type_info = *layerType_getInfo(type);
int flag = 0;
@ -2891,23 +2900,23 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
break;
}
case CD_ASSIGN: {
if (totelem == 0 && cow_to_assign == nullptr) {
if (totelem == 0 && implicit_sharing_info_to_assign == nullptr) {
MEM_SAFE_FREE(layer_data_to_assign);
}
else {
new_layer.data = layer_data_to_assign;
new_layer.cow = cow_to_assign;
if (new_layer.cow) {
new_layer.cow->add_user();
new_layer.implicit_sharing_info = implicit_sharing_info_to_assign;
if (new_layer.implicit_sharing_info) {
new_layer.implicit_sharing_info->add_user();
}
}
break;
}
}
if (new_layer.data != nullptr && new_layer.cow == nullptr) {
if (new_layer.data != nullptr && new_layer.implicit_sharing_info == nullptr) {
/* Make layer data shareable. */
new_layer.cow = make_cow_for_array(type, new_layer.data, totelem);
new_layer.implicit_sharing_info = make_cow_for_array(type, new_layer.data, totelem);
}
new_layer.type = type;
@ -2968,7 +2977,7 @@ const void *CustomData_add_layer_with_data(CustomData *data,
const eCustomDataType type,
void *layer_data,
const int totelem,
const bCopyOnWrite *cow)
const ImplicitSharingInfo *cow)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@ -3004,7 +3013,7 @@ const void *CustomData_add_layer_named_with_data(CustomData *data,
void *layer_data,
int totelem,
const char *name,
const bCopyOnWrite *cow)
const ImplicitSharingInfo *cow)
{
CustomDataLayer *layer = customData_add_layer__internal(
data, type, CD_ASSIGN, layer_data, cow, totelem, name);
@ -3042,7 +3051,7 @@ const void *CustomData_add_layer_anonymous_with_data(
const AnonymousAttributeIDHandle *anonymous_id,
const int totelem,
void *layer_data,
const bCopyOnWrite *cow)
const ImplicitSharingInfo *cow)
{
const char *name = anonymous_id->name().c_str();
CustomDataLayer *layer = customData_add_layer__internal(

View File

@ -1300,22 +1300,26 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh)
return;
}
void *faceset_data = nullptr;
const bCopyOnWrite *faceset_cow = nullptr;
const ImplicitSharingInfo *faceset_implicit_sharing_info = nullptr;
for (const int i : IndexRange(mesh->pdata.totlayer)) {
CustomDataLayer &layer = mesh->pdata.layers[i];
if (layer.type == CD_SCULPT_FACE_SETS) {
faceset_data = layer.data;
faceset_cow = layer.cow;
faceset_implicit_sharing_info = layer.implicit_sharing_info;
layer.data = nullptr;
layer.cow = nullptr;
layer.implicit_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", faceset_cow);
faceset_cow->remove_user_and_delete_if_last();
CustomData_add_layer_named_with_data(&mesh->pdata,
CD_PROP_INT32,
faceset_data,
mesh->totpoly,
".sculpt_face_set",
faceset_implicit_sharing_info);
faceset_implicit_sharing_info->remove_user_and_delete_if_last();
}
}

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup bli
*/
#ifdef __cplusplus
namespace blender {
class ImplicitSharingInfo;
}
using ImplicitSharingInfoHandle = blender::ImplicitSharingInfo;
#else
typedef struct ImplicitSharingInfoHandle ImplicitSharingInfoHandle;
#endif

View File

@ -200,8 +200,6 @@ set(SRC
BLI_compute_context.hh
BLI_console.h
BLI_convexhull_2d.h
BLI_copy_on_write.hh
BLI_copy_on_write_user.hh
BLI_cpp_type.hh
BLI_cpp_type_make.hh
BLI_cpp_types.hh
@ -245,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

View File

@ -102,6 +102,7 @@ extern struct Main *BLO_memfile_main_get(struct MemFile *memfile,
*
* \return success.
*/
extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filepath);
FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction);

View File

@ -16,7 +16,7 @@
#include "DNA_scene_types.h"
#include "BLI_array_utils.h"
#include "BLI_copy_on_write.hh"
#include "BLI_implicit_sharing.hh"
#include "BLI_listbase.h"
#include "BLI_task.hh"
@ -272,16 +272,16 @@ static void um_arraystore_cd_compact(CustomData *cdata,
}
if (layer->data) {
if (layer->cow) {
if (layer->implicit_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. */
BLI_assert(layer->cow->is_mutable());
MEM_delete(layer->cow);
BLI_assert(layer->implicit_sharing_info->is_mutable());
MEM_delete(layer->implicit_sharing_info);
}
MEM_freeN(layer->data);
layer->data = nullptr;
layer->cow = nullptr;
layer->implicit_sharing_info = nullptr;
}
}

View File

@ -11,6 +11,8 @@
#include "DNA_defs.h"
#include "BLI_implicit_sharing.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -25,8 +27,6 @@ using AnonymousAttributeIDHandle = blender::bke::AnonymousAttributeID;
typedef struct AnonymousAttributeIDHandle AnonymousAttributeIDHandle;
#endif
struct bCopyOnWrite;
/** Descriptor and storage for a custom data layer. */
typedef struct CustomDataLayer {
/** Type of data in layer. */
@ -59,7 +59,7 @@ typedef struct CustomDataLayer {
* Run-time data that allows sharing `data` with other entities (mostly custom data layers on
* other geometries).
*/
const struct bCopyOnWrite *cow;
const ImplicitSharingInfoHandle *implicit_sharing_info;
} CustomDataLayer;
#define MAX_CUSTOMDATA_LAYER_NAME 68