progress
This commit is contained in:
parent
e0ac932156
commit
1713a780c5
|
@ -23,6 +23,7 @@
|
|||
#include <atomic>
|
||||
#include <iostream>
|
||||
|
||||
#include "BLI_copy_on_write.h"
|
||||
#include "BLI_float3.hh"
|
||||
#include "BLI_float4x4.hh"
|
||||
#include "BLI_function_ref.hh"
|
||||
|
@ -63,14 +64,13 @@ class GeometryComponent;
|
|||
|
||||
/**
|
||||
* 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.
|
||||
* a user count to allow avoiding duplication when it is wrapped with #bCopyOnWrite. It also
|
||||
* handles the attribute API, which generalizes storing and modifying generic information on a
|
||||
* geometry.
|
||||
*/
|
||||
class GeometryComponent {
|
||||
private:
|
||||
/* The reference count has two purposes. When it becomes zero, the component is freed. When it is
|
||||
* larger than one, the component becomes immutable. */
|
||||
mutable std::atomic<int> users_ = 1;
|
||||
blender::bCopyOnWrite cow_;
|
||||
GeometryComponentType type_;
|
||||
|
||||
public:
|
||||
|
@ -81,14 +81,22 @@ class GeometryComponent {
|
|||
/* The returned component should be of the same type as the type this is called on. */
|
||||
virtual GeometryComponent *copy() const = 0;
|
||||
|
||||
const blender::bCopyOnWrite &cow() const
|
||||
{
|
||||
return cow_;
|
||||
}
|
||||
|
||||
void cow_delete_self() const
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
void user_add() const;
|
||||
void user_remove() const;
|
||||
bool is_mutable() const;
|
||||
|
||||
GeometryComponentType type() const;
|
||||
|
@ -310,7 +318,7 @@ inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryCompon
|
|||
*/
|
||||
struct GeometrySet {
|
||||
private:
|
||||
using GeometryComponentPtr = blender::UserCounter<class GeometryComponent>;
|
||||
using GeometryComponentPtr = blender::COWUser<class GeometryComponent>;
|
||||
/* Indexed by #GeometryComponentType. */
|
||||
std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
|
||||
|
||||
|
|
|
@ -69,24 +69,9 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void GeometryComponent::user_add() const
|
||||
{
|
||||
users_.fetch_add(1);
|
||||
}
|
||||
|
||||
void GeometryComponent::user_remove() const
|
||||
{
|
||||
const int new_users = users_.fetch_sub(1) - 1;
|
||||
if (new_users == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
bool GeometryComponent::is_mutable() const
|
||||
{
|
||||
/* If the item is shared, it is read-only. */
|
||||
/* The user count can be 0, when this is called from the destructor. */
|
||||
return users_ <= 1;
|
||||
return cow_.is_mutable();
|
||||
}
|
||||
|
||||
GeometryComponentType GeometryComponent::type() const
|
||||
|
@ -168,7 +153,7 @@ void GeometrySet::keep_only(const blender::Span<GeometryComponentType> component
|
|||
void GeometrySet::add(const GeometryComponent &component)
|
||||
{
|
||||
BLI_assert(!components_[component.type()]);
|
||||
component.user_add();
|
||||
component.cow().user_add();
|
||||
components_[component.type()] = const_cast<GeometryComponent *>(&component);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
* \ingroup bli
|
||||
*/
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
#include "DNA_copy_on_write.h"
|
||||
|
||||
|
@ -31,11 +33,10 @@ extern "C" {
|
|||
bCopyOnWrite *BLI_cow_new(int user_count);
|
||||
void BLI_cow_free(const bCopyOnWrite *cow);
|
||||
|
||||
void BLI_cow_init(const bCopyOnWrite *cow, int user_count);
|
||||
void BLI_cow_init(const bCopyOnWrite *cow);
|
||||
|
||||
bool BLI_cow_is_shared(const bCopyOnWrite *cow);
|
||||
bool BLI_cow_is_mutable(const bCopyOnWrite *cow);
|
||||
bool BLI_cow_is_zero(const bCopyOnWrite *cow);
|
||||
|
||||
void BLI_cow_user_add(const bCopyOnWrite *cow);
|
||||
bool BLI_cow_user_remove(const bCopyOnWrite *cow) ATTR_WARN_UNUSED_RESULT;
|
||||
|
@ -43,3 +44,179 @@ bool BLI_cow_user_remove(const bCopyOnWrite *cow) ATTR_WARN_UNUSED_RESULT;
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace blender {
|
||||
|
||||
class bCopyOnWrite : public ::bCopyOnWrite, private NonCopyable, NonMovable {
|
||||
public:
|
||||
bCopyOnWrite()
|
||||
{
|
||||
BLI_cow_init(this);
|
||||
}
|
||||
|
||||
~bCopyOnWrite()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
}
|
||||
|
||||
bool is_shared() const
|
||||
{
|
||||
return BLI_cow_is_shared(this);
|
||||
}
|
||||
|
||||
bool is_mutable() const
|
||||
{
|
||||
return BLI_cow_is_mutable(this);
|
||||
}
|
||||
|
||||
void user_add() const
|
||||
{
|
||||
BLI_cow_user_add(this);
|
||||
}
|
||||
|
||||
bool user_remove() const ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return BLI_cow_user_remove(this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class COWUser {
|
||||
private:
|
||||
T *data_ = nullptr;
|
||||
|
||||
public:
|
||||
COWUser() = default;
|
||||
|
||||
COWUser(T *data) : data_(data)
|
||||
{
|
||||
}
|
||||
|
||||
COWUser(const COWUser &other) : data_(other.data_)
|
||||
{
|
||||
this->user_add(data_);
|
||||
}
|
||||
|
||||
COWUser(COWUser &&other) : data_(other.data_)
|
||||
{
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
|
||||
~COWUser()
|
||||
{
|
||||
this->user_remove(data_);
|
||||
}
|
||||
|
||||
COWUser &operator=(const COWUser &other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
this->user_remove(data_);
|
||||
data_ = other.data_;
|
||||
this->user_add(data_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
COWUser &operator=(COWUser &&other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
this->user_remove(data_);
|
||||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *operator->()
|
||||
{
|
||||
BLI_assert(data_ != nullptr);
|
||||
return data_;
|
||||
}
|
||||
|
||||
const T *operator->() const
|
||||
{
|
||||
BLI_assert(data_ != nullptr);
|
||||
return data_;
|
||||
}
|
||||
|
||||
T &operator*()
|
||||
{
|
||||
BLI_assert(data_ != nullptr);
|
||||
return *data_;
|
||||
}
|
||||
|
||||
const T &operator*() const
|
||||
{
|
||||
BLI_assert(data_ != nullptr);
|
||||
return *data_;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return data_ != nullptr;
|
||||
}
|
||||
|
||||
T *get()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const T *get() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
T *release()
|
||||
{
|
||||
T *data = data_;
|
||||
data_ = nullptr;
|
||||
return data;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
this->user_remove(data_);
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
bool has_value() const
|
||||
{
|
||||
return data_ != nullptr;
|
||||
}
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
return get_default_hash(data_);
|
||||
}
|
||||
|
||||
friend bool operator==(const COWUser &a, const COWUser &b)
|
||||
{
|
||||
return a.data_ == b.data_;
|
||||
}
|
||||
|
||||
private:
|
||||
static void user_add(T *data)
|
||||
{
|
||||
if (data != nullptr) {
|
||||
data->cow().user_add();
|
||||
}
|
||||
}
|
||||
|
||||
static void user_remove(T *data)
|
||||
{
|
||||
if (data != nullptr) {
|
||||
if (data->cow().user_remove()) {
|
||||
data->cow_delete_self();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender
|
||||
|
||||
#endif
|
||||
|
|
|
@ -44,9 +44,9 @@ void BLI_cow_free(const bCopyOnWrite *cow)
|
|||
MEM_freeN(const_cast<bCopyOnWrite *>(cow));
|
||||
}
|
||||
|
||||
void BLI_cow_init(const bCopyOnWrite *cow, int user_count)
|
||||
void BLI_cow_init(const bCopyOnWrite *cow)
|
||||
{
|
||||
get_counter(cow) = user_count;
|
||||
get_counter(cow) = 1;
|
||||
}
|
||||
|
||||
bool BLI_cow_is_mutable(const bCopyOnWrite *cow)
|
||||
|
@ -59,11 +59,6 @@ bool BLI_cow_is_shared(const bCopyOnWrite *cow)
|
|||
return cow->user_count >= 2;
|
||||
}
|
||||
|
||||
bool BLI_cow_is_zero(const bCopyOnWrite *cow)
|
||||
{
|
||||
return cow->user_count == 0;
|
||||
}
|
||||
|
||||
void BLI_cow_user_add(const bCopyOnWrite *cow)
|
||||
{
|
||||
atomic_fetch_and_add_int32(&get_counter(cow), 1);
|
||||
|
|
|
@ -191,7 +191,7 @@ struct GatherTasks {
|
|||
|
||||
/* Volumes only have very simple support currently. Only the first found volume is put into the
|
||||
* output. */
|
||||
UserCounter<VolumeComponent> first_volume;
|
||||
COWUser<VolumeComponent> first_volume;
|
||||
};
|
||||
|
||||
/** Current offsets while during the gather operation. */
|
||||
|
@ -480,7 +480,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->user_add();
|
||||
volume_component->cow().user_add();
|
||||
gather_info.r_tasks.first_volume = const_cast<VolumeComponent *>(volume_component);
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue