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
7 changed files with 109 additions and 59 deletions
Showing only changes of commit a66aeb2213 - Show all commits

View File

@ -48,11 +48,29 @@ struct BasisCache {
} // namespace curves::nurbs
template<typename T,
int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T)),
typename Allocator = GuardedAllocator>
class SharedVector : public Vector<T, InlineBufferCapacity, Allocator>,
public ImplicitSharingMixin {
public:
SharedVector() = default;
SharedVector(const int64_t size) : Vector<T, InlineBufferCapacity, Allocator>(size) {}
SharedVector(const Span<T> data) : Vector<T, InlineBufferCapacity, Allocator>(data) {}
void delete_self() override
{
delete this;
}
};
/**
* Contains derived data, caches, and other information not saved in files.
*/
class CurvesGeometryRuntime {
public:
ImplicitSharingPtr<SharedVector<int>> curve_offset_indices;
/**
* The cached number of curves with each type. Unlike other caches here, this is not computed
* lazily, since it is needed so often and types are not adjusted much anyway.
@ -846,7 +864,10 @@ inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts
inline OffsetIndices<int> CurvesGeometry::points_by_curve() const
{
return OffsetIndices<int>({this->curve_offsets, this->curve_num + 1});
if (!this->runtime->curve_offset_indices) {
return {};
}
return OffsetIndices<int>(this->runtime->curve_offset_indices->as_span());
}
inline int CurvesGeometry::evaluated_points_num() const

View File

@ -80,6 +80,9 @@ static KnotsMode knots_mode_from_legacy(const short flag)
Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list)
{
const Vector<const Nurb *> src_curves(nurbs_list);
if (src_curves.is_empty()) {
return nullptr;
}
Curves *curves_id = curves_new_nomain(0, src_curves.size());
CurvesGeometry &curves = curves_id->geometry.wrap();
@ -104,10 +107,6 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
curves.update_curve_types();
if (curves.curves_num() == 0) {
return curves_id;
}
const OffsetIndices points_by_curve = curves.points_by_curve();
MutableSpan<float3> positions = curves.positions_for_write();
SpanAttributeWriter<float> radius_attribute =

View File

@ -70,36 +70,13 @@ static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, con
const Curves *curves_src = (const Curves *)id_src;
curves_dst->mat = static_cast<Material **>(MEM_dupallocN(curves_src->mat));
const bke::CurvesGeometry &src = curves_src->geometry.wrap();
bke::CurvesGeometry &dst = curves_dst->geometry.wrap();
/* We need special handling here because the generic ID management code has already done a
* shallow copy from the source to the destination, and because the copy-on-write functionality
* isn't supported more generically yet. */
dst.point_num = src.point_num;
dst.curve_num = src.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));
new (&curves_dst->geometry) bke::CurvesGeometry(curves_src->geometry.wrap());
BLI_assert(curves_dst->geometry.runtime->curve_offset_indices->is_shared());
if (curves_src->surface_uv_map != nullptr) {
curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map);
}
dst.runtime = MEM_new<bke::CurvesGeometryRuntime>(__func__);
dst.runtime->type_counts = src.runtime->type_counts;
dst.runtime->evaluated_offsets_cache = src.runtime->evaluated_offsets_cache;
dst.runtime->nurbs_basis_cache = src.runtime->nurbs_basis_cache;
dst.runtime->evaluated_position_cache = src.runtime->evaluated_position_cache;
dst.runtime->bounds_cache = src.runtime->bounds_cache;
dst.runtime->evaluated_length_cache = src.runtime->evaluated_length_cache;
dst.runtime->evaluated_tangent_cache = src.runtime->evaluated_tangent_cache;
dst.runtime->evaluated_normal_cache = src.runtime->evaluated_normal_cache;
curves_dst->batch_cache = nullptr;
}
@ -155,11 +132,6 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &curves->surface_uv_map);
curves->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
/* Recalculate curve type count cache that isn't saved in files. */
curves->geometry.wrap().update_curve_types();
/* Materials */
BLO_read_pointer_array(reader, (void **)&curves->mat);
}

View File

@ -60,13 +60,16 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num)
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
this->offsets_for_write().fill(-1);
#endif
this->offsets_for_write().first() = 0;
this->runtime = MEM_new<CurvesGeometryRuntime>(__func__);
if (curve_num > 0) {
this->runtime->curve_offset_indices = new SharedVector<int>(this->curve_num + 1);
#ifdef DEBUG
this->offsets_for_write().fill(-1);
#endif
this->offsets_for_write().first() = 0;
}
/* Fill the type counts with the default so they're in a valid state. */
this->runtime->type_counts[CURVE_TYPE_CATMULL_ROM] = curve_num;
}
@ -83,9 +86,7 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src)
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__);
dst.offsets_for_write().copy_from(src.offsets());
dst.runtime->curve_offset_indices = src.runtime->curve_offset_indices;
dst.tag_topology_changed();
@ -100,8 +101,7 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src)
dst.runtime->evaluated_normal_cache = src.runtime->evaluated_normal_cache;
}
CurvesGeometry::CurvesGeometry(const CurvesGeometry &other)
: CurvesGeometry(other.point_num, other.curve_num)
CurvesGeometry::CurvesGeometry(const CurvesGeometry &other) : CurvesGeometry()
{
copy_curves_geometry(*this, other);
}
@ -127,14 +127,10 @@ static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src)
CustomData_free(&src.curve_data, src.curve_num);
src.curve_num = 0;
std::swap(dst.curve_offsets, src.curve_offsets);
MEM_SAFE_FREE(src.curve_offsets);
std::swap(dst.runtime, src.runtime);
}
CurvesGeometry::CurvesGeometry(CurvesGeometry &&other)
: CurvesGeometry(other.point_num, other.curve_num)
CurvesGeometry::CurvesGeometry(CurvesGeometry &&other) : CurvesGeometry()
{
move_curves_geometry(*this, other);
}
@ -151,7 +147,6 @@ CurvesGeometry::~CurvesGeometry()
{
CustomData_free(&this->point_data, this->point_num);
CustomData_free(&this->curve_data, this->curve_num);
MEM_SAFE_FREE(this->curve_offsets);
MEM_delete(this->runtime);
this->runtime = nullptr;
}
@ -324,11 +319,19 @@ MutableSpan<float3> CurvesGeometry::positions_for_write()
Span<int> CurvesGeometry::offsets() const
{
return {this->curve_offsets, this->curve_num + 1};
return this->runtime->curve_offset_indices->as_span();
}
MutableSpan<int> CurvesGeometry::offsets_for_write()
{
return {this->curve_offsets, this->curve_num + 1};
if (!this->runtime->curve_offset_indices) {
return {};
}
if (this->runtime->curve_offset_indices->is_shared()) {
SharedVector<int> *data = new SharedVector<int>(this->runtime->curve_offset_indices);
this->runtime->curve_offset_indices = data;
}
return this->runtime->curve_offset_indices->as_mutable_span();
}
VArray<bool> CurvesGeometry::cyclic() const
@ -950,8 +953,23 @@ void CurvesGeometry::resize(const int points_num, const int curves_num)
}
if (curves_num != this->curve_num) {
CustomData_realloc(&this->curve_data, this->curves_num(), curves_num);
if (!this->runtime->curve_offset_indices) {
this->runtime->curve_offset_indices = new SharedVector<int>(curves_num + 1);
this->runtime->curve_offset_indices->first() = 0;
this->runtime->curve_offset_indices->last() = points_num;
}
else if (this->runtime->curve_offset_indices->is_mutable()) {
this->runtime->curve_offset_indices->resize(curves_num + 1);
this->runtime->curve_offset_indices->last() = points_num;
}
else {
SharedVector<int> *new_offsets = new SharedVector<int>(curves_num + 1);
new_offsets->as_mutable_span()
.take_front(this->curve_num + 1)
.copy_from({this->curve_offsets, this->curve_num + 1});
this->runtime->curve_offset_indices = new_offsets;
}
this->curve_num = curves_num;
this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1));
}
this->tag_topology_changed();
}
@ -1585,7 +1603,15 @@ void CurvesGeometry::blend_read(BlendDataReader &reader)
CustomData_blend_read(&reader, &this->point_data, this->point_num);
CustomData_blend_read(&reader, &this->curve_data, this->curve_num);
this->runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets);
SharedVector<int> *vector = new SharedVector<int>({this->curve_offsets, this->curve_num + 1});
this->runtime->curve_offset_indices = ImplicitSharingPtr(vector);
MEM_SAFE_FREE(this->curve_offsets);
/* Recalculate curve type count cache that isn't saved in files. */
this->update_curve_types();
}
void CurvesGeometry::blend_write(BlendWriter &writer, ID &id)
@ -1600,6 +1626,7 @@ void CurvesGeometry::blend_write(BlendWriter &writer, ID &id)
CustomData_blend_write(
&writer, &this->curve_data, curve_layers, this->curve_num, CD_MASK_ALL, &id);
this->curve_offsets = this->runtime->curve_offset_indices->data();
BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets);
}

View File

@ -57,3 +57,8 @@ void ED_curves_transverts_create(Curves *curves_id, TransVertStore *tvs)
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
ed::curves::transverts_from_curves_positions_create(curves, tvs);
}
int *ED_curves_offsets_for_write(struct Curves *curves_id)
{
return curves_id->geometry.wrap().offsets_for_write().data();
}

View File

@ -38,6 +38,8 @@ float (*ED_curves_point_normals_array_create(const struct Curves *curves_id))[3]
*/
void ED_curves_transverts_create(struct Curves *curves_id, struct TransVertStore *tvs);
int *ED_curves_offsets_for_write(struct Curves *curves_id);
/** \} */
#ifdef __cplusplus

View File

@ -68,9 +68,9 @@ static int rna_Curves_curve_offset_data_length(PointerRNA *ptr)
static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
Curves *curves = rna_curves(ptr);
rna_iterator_array_begin(iter,
(void *)curves->geometry.curve_offsets,
ED_curves_offsets_for_write(curves),
sizeof(int),
curves->geometry.curve_num + 1,
false,
@ -97,6 +97,23 @@ static int rna_CurvePoint_index_get_const(const PointerRNA *ptr)
return (int)(co - positions);
}
static void rna_Curves_curves_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Curves *curves = rna_curves(ptr);
rna_iterator_array_begin(iter,
ED_curves_offsets_for_write(curves),
sizeof(int),
curves->geometry.curve_num,
false,
NULL);
}
static int rna_Curves_curves_length(PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
return curves->geometry.curve_num;
}
static int rna_Curves_position_data_length(PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
@ -343,7 +360,15 @@ static void rna_def_curves(BlenderRNA *brna)
/* Point and Curve RNA API helpers. */
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", "geometry.curve_num");
RNA_def_property_collection_funcs(prop,
"rna_Curves_curves_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_Curves_curves_length",
NULL,
NULL,
NULL);
RNA_def_property_struct_type(prop, "CurveSlice");
RNA_def_property_ui_text(prop, "Curves", "All curves in the data-block");
@ -376,7 +401,6 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Curves_update_data");
prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", NULL);
RNA_def_property_struct_type(prop, "IntAttributeValue");
RNA_def_property_collection_funcs(prop,
"rna_Curves_curve_offset_data_begin",