Simulation Nodes: bake simulation states to disk #106937
|
@ -34,18 +34,34 @@ class BDataWriter {
|
|||
|
||||
class BDataSharing {
|
||||
private:
|
||||
struct StoredValue {
|
||||
struct StoredByRuntimeValue {
|
||||
int64_t sharing_info_version;
|
||||
DictionaryValuePtr io_data;
|
||||
};
|
||||
|
||||
Map<const ImplicitSharingInfo *, StoredValue> map_;
|
||||
struct RuntimeByStoredValue {
|
||||
const ImplicitSharingInfo *sharing_info;
|
||||
int64_t sharing_info_version;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
/** The #ImplicitSharingInfo pointer is a weak user. */
|
||||
Map<const ImplicitSharingInfo *, StoredByRuntimeValue> stored_by_runtime_;
|
||||
Map<std::string, RuntimeByStoredValue> runtime_by_stored_;
|
||||
|
||||
public:
|
||||
~BDataSharing();
|
||||
|
||||
DictionaryValuePtr write_shared(const ImplicitSharingInfo *sharing_info,
|
||||
FunctionRef<DictionaryValuePtr()> write_fn);
|
||||
|
||||
struct SharingInfoWithData {
|
||||
const ImplicitSharingInfo *sharing_info;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
SharingInfoWithData read_shared(const DictionaryValue &io_data,
|
||||
FunctionRef<SharingInfoWithData()> read_fn);
|
||||
};
|
||||
|
||||
class DiskBDataReader : public BDataReader {
|
||||
|
|
|
@ -781,9 +781,14 @@ BDataSlice DiskBDataWriter::write(const void *data, const int64_t size)
|
|||
|
||||
BDataSharing::~BDataSharing()
|
||||
{
|
||||
for (const ImplicitSharingInfo *sharing_info : map_.keys()) {
|
||||
for (const ImplicitSharingInfo *sharing_info : stored_by_runtime_.keys()) {
|
||||
sharing_info->remove_weak_user_and_delete_if_last();
|
||||
}
|
||||
for (const RuntimeByStoredValue &value : runtime_by_stored_.values()) {
|
||||
if (value.sharing_info) {
|
||||
value.sharing_info->remove_weak_user_and_delete_if_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DictionaryValuePtr BDataSharing::write_shared(const ImplicitSharingInfo *sharing_info,
|
||||
|
@ -792,18 +797,18 @@ DictionaryValuePtr BDataSharing::write_shared(const ImplicitSharingInfo *sharing
|
|||
if (sharing_info == nullptr) {
|
||||
return write_fn();
|
||||
}
|
||||
return map_.add_or_modify(
|
||||
return stored_by_runtime_.add_or_modify(
|
||||
sharing_info,
|
||||
/* Create new value. */
|
||||
[&](StoredValue *value) {
|
||||
new (value) StoredValue();
|
||||
[&](StoredByRuntimeValue *value) {
|
||||
new (value) StoredByRuntimeValue();
|
||||
value->io_data = write_fn();
|
||||
value->sharing_info_version = sharing_info->version();
|
||||
sharing_info->add_weak_user();
|
||||
return value->io_data;
|
||||
},
|
||||
/* Potentially modify existing value. */
|
||||
[&](StoredValue *value) {
|
||||
[&](StoredByRuntimeValue *value) {
|
||||
const int64_t new_version = sharing_info->version();
|
||||
BLI_assert(value->sharing_info_version <= new_version);
|
||||
if (value->sharing_info_version < new_version) {
|
||||
|
@ -814,4 +819,50 @@ DictionaryValuePtr BDataSharing::write_shared(const ImplicitSharingInfo *sharing
|
|||
});
|
||||
}
|
||||
|
||||
BDataSharing::SharingInfoWithData BDataSharing::read_shared(
|
||||
const DictionaryValue &io_data, FunctionRef<SharingInfoWithData()> read_fn)
|
||||
{
|
||||
io::serialize::JsonFormatter formatter;
|
||||
std::stringstream ss;
|
||||
formatter.serialize(ss, io_data);
|
||||
const std::string key = ss.str();
|
||||
|
||||
return runtime_by_stored_.add_or_modify_as(
|
||||
key,
|
||||
[&](RuntimeByStoredValue *value) {
|
||||
new (value) RuntimeByStoredValue();
|
||||
const SharingInfoWithData data = read_fn();
|
||||
value->sharing_info = data.sharing_info;
|
||||
if (value->sharing_info != nullptr) {
|
||||
value->sharing_info->add_weak_user();
|
||||
value->sharing_info_version = value->sharing_info->version();
|
||||
}
|
||||
value->data = data.data;
|
||||
return data;
|
||||
},
|
||||
[&](RuntimeByStoredValue *value) {
|
||||
/* Try to use existing data. */
|
||||
if (value->sharing_info) {
|
||||
if (value->sharing_info->add_user_if_not_expired()) {
|
||||
if (value->sharing_info_version == value->sharing_info->version()) {
|
||||
return SharingInfoWithData{value->sharing_info, value->data};
|
||||
}
|
||||
value->sharing_info->remove_user_and_delete_if_last();
|
||||
}
|
||||
value->sharing_info->remove_weak_user_and_delete_if_last();
|
||||
value->sharing_info = nullptr;
|
||||
}
|
||||
|
||||
/* Can't use existing data, load again. */
|
||||
const SharingInfoWithData data = read_fn();
|
||||
value->sharing_info = data.sharing_info;
|
||||
if (value->sharing_info) {
|
||||
value->sharing_info->add_weak_user();
|
||||
value->sharing_info_version = value->sharing_info->version();
|
||||
}
|
||||
value->data = data.data;
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace blender::bke::sim
|
||||
|
|
|
@ -53,7 +53,7 @@ class ImplicitSharingInfo : NonCopyable, NonMovable {
|
|||
* incremented whenever the referenced data is about to be changed. This allows weak users to
|
||||
* detect if the data has changed since the weak user was created.
|
||||
*/
|
||||
mutable int64_t version_ = 0;
|
||||
mutable std::atomic<int64_t> version_ = 0;
|
||||
|
||||
public:
|
||||
virtual ~ImplicitSharingInfo()
|
||||
|
@ -126,7 +126,7 @@ class ImplicitSharingInfo : NonCopyable, NonMovable {
|
|||
BLI_assert(this->is_mutable());
|
||||
/* Does not need an atomic increment, because if the data is mutable, there is only a single
|
||||
* owner that may call this at a time. */
|
||||
version_++;
|
||||
version_.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,7 +136,7 @@ class ImplicitSharingInfo : NonCopyable, NonMovable {
|
|||
*/
|
||||
int64_t version() const
|
||||
{
|
||||
return version_;
|
||||
return version_.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue