WIP: use generic copy-on-write system to avoid unnecessary data copies #104470
|
@ -10,24 +10,6 @@
|
|||
|
||||
namespace blender::bke {
|
||||
|
||||
class AnonymousAttributeID;
|
||||
|
||||
class AnonymousAttributeIDCOW : public bCopyOnWrite {
|
||||
private:
|
||||
AnonymousAttributeID *id_;
|
||||
|
||||
public:
|
||||
AnonymousAttributeIDCOW(AnonymousAttributeID *id) : bCopyOnWrite(1), id_(id)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void delete_self_with_data() override
|
||||
{
|
||||
MEM_delete(id_);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An #AnonymousAttributeID contains information about a specific anonymous attribute.
|
||||
* Like normal attributes, anonymous attributes are also identified by their name, so one should
|
||||
|
@ -50,10 +32,7 @@ class AnonymousAttributeIDCOW : public bCopyOnWrite {
|
|||
* 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:
|
||||
AnonymousAttributeIDCOW cow_;
|
||||
|
||||
class AnonymousAttributeID : public bCopyOnWriteMixin<AnonymousAttributeID> {
|
||||
protected:
|
||||
std::string name_;
|
||||
|
||||
|
@ -68,12 +47,7 @@ class AnonymousAttributeID {
|
|||
|
||||
virtual std::string user_name() const;
|
||||
|
||||
const bCopyOnWrite &cow() const
|
||||
{
|
||||
return cow_;
|
||||
}
|
||||
|
||||
void cow_delete_self() const
|
||||
void delete_self() const
|
||||
{
|
||||
MEM_delete(this);
|
||||
}
|
||||
|
|
|
@ -38,30 +38,14 @@ class CurvesEditHints;
|
|||
class Instances;
|
||||
} // namespace blender::bke
|
||||
|
||||
class GeometryComponent;
|
||||
|
||||
class GeometryComponentCOW : public bCopyOnWrite {
|
||||
private:
|
||||
GeometryComponent *component_;
|
||||
|
||||
public:
|
||||
GeometryComponentCOW(GeometryComponent *component) : bCopyOnWrite(1), component_(component)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void delete_self_with_data() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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:
|
||||
GeometryComponentType type_;
|
||||
GeometryComponentCOW cow_;
|
||||
|
||||
public:
|
||||
GeometryComponent(GeometryComponentType type);
|
||||
|
@ -80,22 +64,20 @@ class GeometryComponent {
|
|||
/* The returned component should be of the same type as the type this is called on. */
|
||||
virtual GeometryComponent *copy() const = 0;
|
||||
|
||||
const bCopyOnWrite &cow() const
|
||||
{
|
||||
return cow_;
|
||||
}
|
||||
|
||||
/* Direct data is everything except for instances of objects/collections.
|
||||
* If this returns true, the geometry set can be cached and is still valid after e.g. modifier
|
||||
* evaluation ends. Instances can only be valid as long as the data they instance is valid. */
|
||||
virtual bool owns_direct_data() const = 0;
|
||||
virtual void ensure_owns_direct_data() = 0;
|
||||
|
||||
bool is_mutable() const;
|
||||
|
||||
GeometryComponentType type() const;
|
||||
|
||||
virtual bool is_empty() const;
|
||||
|
||||
void delete_self()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
namespace blender::bke {
|
||||
|
||||
AnonymousAttributeID::AnonymousAttributeID() : cow_(this)
|
||||
{
|
||||
}
|
||||
AnonymousAttributeID::AnonymousAttributeID() = default;
|
||||
|
||||
std::string AnonymousAttributeID::user_name() const
|
||||
{
|
||||
|
|
|
@ -2297,7 +2297,7 @@ static bool customdata_merge_internal(const CustomData *source,
|
|||
|
||||
if (src_layer.anonymous_id != nullptr) {
|
||||
new_layer->anonymous_id = src_layer.anonymous_id;
|
||||
new_layer->anonymous_id->cow().add_user();
|
||||
new_layer->anonymous_id->add_user();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2473,7 +2473,7 @@ void CustomData_copy_without_data(const struct CustomData *source,
|
|||
static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem)
|
||||
{
|
||||
if (layer->anonymous_id != nullptr) {
|
||||
layer->anonymous_id->cow().remove_user_and_delete_if_last();
|
||||
layer->anonymous_id->remove_user_and_delete_if_last();
|
||||
layer->anonymous_id = nullptr;
|
||||
}
|
||||
const eCustomDataType type = eCustomDataType(layer->type);
|
||||
|
@ -2998,7 +2998,7 @@ void *CustomData_add_layer_anonymous(CustomData *data,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
anonymous_id->cow().add_user();
|
||||
anonymous_id->add_user();
|
||||
layer->anonymous_id = anonymous_id;
|
||||
return layer->data;
|
||||
}
|
||||
|
@ -3019,7 +3019,7 @@ const void *CustomData_add_layer_anonymous_with_existing_data(
|
|||
if (layer == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
anonymous_id->cow().add_user();
|
||||
anonymous_id->add_user();
|
||||
layer->anonymous_id = anonymous_id;
|
||||
return layer->data;
|
||||
}
|
||||
|
|
|
@ -35,16 +35,11 @@ using blender::Vector;
|
|||
using blender::bke::InstanceReference;
|
||||
using blender::bke::Instances;
|
||||
|
||||
void GeometryComponentCOW::delete_self_with_data()
|
||||
{
|
||||
delete component_;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Component
|
||||
* \{ */
|
||||
|
||||
GeometryComponent::GeometryComponent(GeometryComponentType type) : type_(type), cow_(this)
|
||||
GeometryComponent::GeometryComponent(GeometryComponentType type) : type_(type)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -89,11 +84,6 @@ std::optional<blender::bke::MutableAttributeAccessor> GeometryComponent::attribu
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool GeometryComponent::is_mutable() const
|
||||
{
|
||||
return cow_.is_mutable();
|
||||
}
|
||||
|
||||
GeometryComponentType GeometryComponent::type() const
|
||||
{
|
||||
return type_;
|
||||
|
@ -188,7 +178,7 @@ void GeometrySet::remove_geometry_during_modify()
|
|||
void GeometrySet::add(const GeometryComponent &component)
|
||||
{
|
||||
BLI_assert(!components_[component.type()]);
|
||||
component.cow().add_user();
|
||||
component.add_user();
|
||||
components_[component.type()] = const_cast<GeometryComponent *>(&component);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,3 +55,18 @@ struct bCopyOnWrite : blender::NonCopyable, blender::NonMovable {
|
|||
private:
|
||||
virtual void delete_self_with_data() = 0;
|
||||
};
|
||||
|
||||
template<typename T> struct bCopyOnWriteMixin : public bCopyOnWrite {
|
||||
public:
|
||||
bCopyOnWriteMixin() : bCopyOnWrite(1)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void delete_self_with_data() override
|
||||
{
|
||||
static_assert(std::is_base_of_v<bCopyOnWriteMixin<T>, T>);
|
||||
T *data = static_cast<T *>(this);
|
||||
data->delete_self();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -131,14 +131,14 @@ template<typename T> class COWUser {
|
|||
static void add_user(T *data)
|
||||
{
|
||||
if (data != nullptr) {
|
||||
data->cow().add_user();
|
||||
data->add_user();
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_user_and_delete_if_last(T *data)
|
||||
{
|
||||
if (data != nullptr) {
|
||||
data->cow().remove_user_and_delete_if_last();
|
||||
data->remove_user_and_delete_if_last();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -82,7 +82,7 @@ static void add_new_edges(Mesh &mesh,
|
|||
}
|
||||
else {
|
||||
anonymous_ids.append(&id.anonymous_id());
|
||||
id.anonymous_id().cow().add_user();
|
||||
id.anonymous_id().add_user();
|
||||
}
|
||||
}
|
||||
Vector<bke::AttributeIDRef> local_edge_ids;
|
||||
|
|
|
@ -598,7 +598,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||
case GEO_COMPONENT_TYPE_VOLUME: {
|
||||
const VolumeComponent *volume_component = static_cast<const VolumeComponent *>(component);
|
||||
if (!gather_info.r_tasks.first_volume) {
|
||||
volume_component->cow().add_user();
|
||||
volume_component->add_user();
|
||||
gather_info.r_tasks.first_volume = const_cast<VolumeComponent *>(volume_component);
|
||||
}
|
||||
break;
|
||||
|
@ -607,7 +607,7 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
|
|||
const GeometryComponentEditData *edit_component =
|
||||
static_cast<const GeometryComponentEditData *>(component);
|
||||
if (!gather_info.r_tasks.first_edit_data) {
|
||||
edit_component->cow().add_user();
|
||||
edit_component->add_user();
|
||||
gather_info.r_tasks.first_edit_data = edit_component;
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue