WIP: Attributes: avoid unnecessary data copies by generalizing attribute unshare policy #119588
|
@ -10,6 +10,7 @@
|
|||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_generic_span.hh"
|
||||
#include "BLI_generic_virtual_array.hh"
|
||||
#include "BLI_implicit_sharing_unshare.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_struct_equality_utils.hh"
|
||||
|
@ -426,7 +427,9 @@ struct AttributeAccessorFunctions {
|
|||
bool (*for_all)(const void *owner,
|
||||
FunctionRef<bool(const AttributeIDRef &, const AttributeMetaData &)> fn);
|
||||
AttributeValidator (*lookup_validator)(const void *owner, const AttributeIDRef &attribute_id);
|
||||
GAttributeWriter (*lookup_for_write)(void *owner, const AttributeIDRef &attribute_id);
|
||||
GAttributeWriter (*lookup_for_write)(void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy);
|
||||
bool (*remove)(void *owner, const AttributeIDRef &attribute_id);
|
||||
bool (*add)(void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
|
@ -642,20 +645,27 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
* Get a writable attribute or none if it does not exist.
|
||||
* Make sure to call #finish after changes are done.
|
||||
*/
|
||||
GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id);
|
||||
GAttributeWriter lookup_for_write(
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy());
|
||||
|
||||
/**
|
||||
* Same as above, but returns a type that makes it easier to work with the attribute as a span.
|
||||
*/
|
||||
GSpanAttributeWriter lookup_for_write_span(const AttributeIDRef &attribute_id);
|
||||
GSpanAttributeWriter lookup_for_write_span(
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy());
|
||||
|
||||
/**
|
||||
* Get a writable attribute or non if it does not exist.
|
||||
* Make sure to call #finish after changes are done.
|
||||
*/
|
||||
template<typename T> AttributeWriter<T> lookup_for_write(const AttributeIDRef &attribute_id)
|
||||
template<typename T>
|
||||
AttributeWriter<T> lookup_for_write(
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy())
|
||||
{
|
||||
GAttributeWriter attribute = this->lookup_for_write(attribute_id);
|
||||
GAttributeWriter attribute = this->lookup_for_write(attribute_id, unshare_policy);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
|
@ -669,9 +679,11 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
* Same as above, but returns a type that makes it easier to work with the attribute as a span.
|
||||
*/
|
||||
template<typename T>
|
||||
SpanAttributeWriter<T> lookup_for_write_span(const AttributeIDRef &attribute_id)
|
||||
SpanAttributeWriter<T> lookup_for_write_span(
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy())
|
||||
{
|
||||
AttributeWriter<T> attribute = this->lookup_for_write<T>(attribute_id);
|
||||
AttributeWriter<T> attribute = this->lookup_for_write<T>(attribute_id, unshare_policy);
|
||||
if (attribute) {
|
||||
return SpanAttributeWriter<T>{std::move(attribute), true};
|
||||
}
|
||||
|
@ -714,7 +726,8 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
const AttributeIDRef &attribute_id,
|
||||
const AttrDomain domain,
|
||||
const eCustomDataType data_type,
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue());
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue(),
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy());
|
||||
|
||||
/**
|
||||
* Same as above, but returns a type that makes it easier to work with the attribute as a span.
|
||||
|
@ -725,7 +738,8 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
const AttributeIDRef &attribute_id,
|
||||
const AttrDomain domain,
|
||||
const eCustomDataType data_type,
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue());
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue(),
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy());
|
||||
|
||||
/**
|
||||
* Same as above, but should be used when the type is known at compile time.
|
||||
|
@ -734,11 +748,14 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
AttributeWriter<T> lookup_or_add_for_write(
|
||||
const AttributeIDRef &attribute_id,
|
||||
const AttrDomain domain,
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue())
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue(),
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy())
|
||||
{
|
||||
const CPPType &cpp_type = CPPType::get<T>();
|
||||
const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
|
||||
return this->lookup_or_add_for_write(attribute_id, domain, data_type, initializer).typed<T>();
|
||||
return this
|
||||
->lookup_or_add_for_write(attribute_id, domain, data_type, initializer, unshare_policy)
|
||||
.typed<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -748,10 +765,11 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
SpanAttributeWriter<T> lookup_or_add_for_write_span(
|
||||
const AttributeIDRef &attribute_id,
|
||||
const AttrDomain domain,
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue())
|
||||
const AttributeInit &initializer = AttributeInitDefaultValue(),
|
||||
const ArrayUnsharePolicy &unshare_policy = DefaultArrayUnsharePolicy())
|
||||
{
|
||||
AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(
|
||||
attribute_id, domain, initializer);
|
||||
attribute_id, domain, initializer, unshare_policy);
|
||||
if (attribute) {
|
||||
return SpanAttributeWriter<T>{std::move(attribute), true};
|
||||
}
|
||||
|
@ -780,7 +798,10 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
const AttrDomain domain)
|
||||
{
|
||||
AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(
|
||||
attribute_id, domain, AttributeInitConstruct());
|
||||
attribute_id,
|
||||
domain,
|
||||
AttributeInitConstruct(),
|
||||
implicit_sharing::unshare::IgnoreOldValues());
|
||||
|
||||
if (attribute) {
|
||||
return SpanAttributeWriter<T>{std::move(attribute), false};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "BLI_cpp_type.hh"
|
||||
#include "BLI_implicit_sharing.h"
|
||||
#include "BLI_implicit_sharing_unshare.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
@ -464,24 +465,75 @@ void CustomData_bmesh_interp(CustomData *data,
|
|||
*/
|
||||
void CustomData_swap_corners(CustomData *data, int index, const int *corner_indices);
|
||||
|
||||
class CustomDataUnsharePolicy {
|
||||
public:
|
||||
void unshare_data(CustomDataLayer &layer, int totelem) const
|
||||
{
|
||||
void *old_data = layer.data;
|
||||
this->unshare_data_impl(layer, totelem);
|
||||
BLI_assert(totelem == 0 || old_data != layer.data);
|
||||
UNUSED_VARS_NDEBUG(old_data);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void unshare_data_impl(CustomDataLayer &layer, int totelem) const = 0;
|
||||
};
|
||||
|
||||
class CustomDataUnsharePolicy_CopyAll : public CustomDataUnsharePolicy {
|
||||
void unshare_data_impl(CustomDataLayer &layer, int totelem) const override;
|
||||
};
|
||||
|
||||
class CustomDataUnsharePolicy_ArrayUnsharePolicy : public CustomDataUnsharePolicy {
|
||||
private:
|
||||
const blender::ArrayUnsharePolicy &array_unshare_policy_;
|
||||
|
||||
public:
|
||||
CustomDataUnsharePolicy_ArrayUnsharePolicy(
|
||||
const blender::ArrayUnsharePolicy &array_unshare_policy)
|
||||
: array_unshare_policy_(array_unshare_policy)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void unshare_data_impl(CustomDataLayer &layer, int totelem) const override;
|
||||
};
|
||||
|
||||
using DefaultCustomDataUnsharePolicy = CustomDataUnsharePolicy_CopyAll;
|
||||
|
||||
/**
|
||||
* Custom data layers can be shared through implicit sharing (`BLI_implicit_sharing.h`). This
|
||||
* function makes sure that the layer is unshared if it was shared, which makes it mutable.
|
||||
*/
|
||||
void CustomData_ensure_data_is_mutable(CustomDataLayer *layer, int totelem);
|
||||
void CustomData_ensure_layers_are_mutable(CustomData *data, int totelem);
|
||||
void CustomData_ensure_data_is_mutable(
|
||||
CustomDataLayer *layer,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy = DefaultCustomDataUnsharePolicy());
|
||||
void CustomData_ensure_layers_are_mutable(
|
||||
CustomData *data,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy = DefaultCustomDataUnsharePolicy());
|
||||
|
||||
/**
|
||||
* Retrieve a pointer to an element of the active layer of the given \a type, chosen by the
|
||||
* \a index, if it exists.
|
||||
*/
|
||||
void *CustomData_get_for_write(CustomData *data, int index, eCustomDataType type, int totelem);
|
||||
void *CustomData_get_for_write(
|
||||
CustomData *data,
|
||||
int index,
|
||||
eCustomDataType type,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy = DefaultCustomDataUnsharePolicy());
|
||||
/**
|
||||
* Retrieve a pointer to an element of the \a nth layer of the given \a type, chosen by the
|
||||
* \a index, if it exists.
|
||||
*/
|
||||
void *CustomData_get_n_for_write(
|
||||
CustomData *data, eCustomDataType type, int index, int n, int totelem);
|
||||
CustomData *data,
|
||||
eCustomDataType type,
|
||||
int index,
|
||||
int n,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy = DefaultCustomDataUnsharePolicy());
|
||||
|
||||
/* BMesh Custom Data Functions.
|
||||
* Should replace edit-mesh ones with these as well, due to more efficient memory alloc. */
|
||||
|
@ -506,14 +558,23 @@ const char *CustomData_get_layer_name(const CustomData *data, eCustomDataType ty
|
|||
* otherwise.
|
||||
*/
|
||||
const void *CustomData_get_layer(const CustomData *data, eCustomDataType type);
|
||||
void *CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem);
|
||||
void *CustomData_get_layer_for_write(
|
||||
CustomData *data,
|
||||
eCustomDataType type,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy = DefaultCustomDataUnsharePolicy());
|
||||
|
||||
/**
|
||||
* Retrieve the data array of the \a nth layer of the given \a type, if it exists. Return null
|
||||
* otherwise.
|
||||
*/
|
||||
const void *CustomData_get_layer_n(const CustomData *data, eCustomDataType type, int n);
|
||||
void *CustomData_get_layer_n_for_write(CustomData *data, eCustomDataType type, int n, int totelem);
|
||||
void *CustomData_get_layer_n_for_write(
|
||||
CustomData *data,
|
||||
eCustomDataType type,
|
||||
int n,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy = DefaultCustomDataUnsharePolicy());
|
||||
|
||||
/**
|
||||
* Retrieve the data array of the layer with the given \a name and \a type, if it exists. Return
|
||||
|
@ -522,10 +583,12 @@ void *CustomData_get_layer_n_for_write(CustomData *data, eCustomDataType type, i
|
|||
const void *CustomData_get_layer_named(const CustomData *data,
|
||||
eCustomDataType type,
|
||||
blender::StringRef name);
|
||||
void *CustomData_get_layer_named_for_write(CustomData *data,
|
||||
eCustomDataType type,
|
||||
blender::StringRef name,
|
||||
int totelem);
|
||||
void *CustomData_get_layer_named_for_write(
|
||||
CustomData *data,
|
||||
eCustomDataType type,
|
||||
blender::StringRef name,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy = DefaultCustomDataUnsharePolicy());
|
||||
|
||||
int CustomData_get_offset(const CustomData *data, eCustomDataType type);
|
||||
int CustomData_get_offset_named(const CustomData *data,
|
||||
|
|
|
@ -430,7 +430,8 @@ GAttributeReader BuiltinCustomDataLayerProvider::try_get_for_read(const void *ow
|
|||
return {GVArray::ForSpan({type, layer.data, element_num}), domain_, layer.sharing_info};
|
||||
}
|
||||
|
||||
GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) const
|
||||
GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(
|
||||
void *owner, const ArrayUnsharePolicy &unshare_policy) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
||||
if (custom_data == nullptr) {
|
||||
|
@ -454,10 +455,19 @@ GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner)
|
|||
|
||||
void *data = nullptr;
|
||||
if (stored_as_named_attribute_) {
|
||||
data = CustomData_get_layer_named_for_write(custom_data, stored_type_, name_, element_num);
|
||||
data = CustomData_get_layer_named_for_write(
|
||||
custom_data,
|
||||
stored_type_,
|
||||
name_,
|
||||
element_num,
|
||||
CustomDataUnsharePolicy_ArrayUnsharePolicy(unshare_policy));
|
||||
}
|
||||
else {
|
||||
data = CustomData_get_layer_for_write(custom_data, stored_type_, element_num);
|
||||
data = CustomData_get_layer_for_write(
|
||||
custom_data,
|
||||
stored_type_,
|
||||
element_num,
|
||||
CustomDataUnsharePolicy_ArrayUnsharePolicy(unshare_policy));
|
||||
}
|
||||
if (data == nullptr) {
|
||||
return {};
|
||||
|
@ -563,7 +573,9 @@ GAttributeReader CustomDataAttributeProvider::try_get_for_read(
|
|||
}
|
||||
|
||||
GAttributeWriter CustomDataAttributeProvider::try_get_for_write(
|
||||
void *owner, const AttributeIDRef &attribute_id) const
|
||||
void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
||||
if (custom_data == nullptr) {
|
||||
|
@ -575,7 +587,11 @@ GAttributeWriter CustomDataAttributeProvider::try_get_for_write(
|
|||
continue;
|
||||
}
|
||||
CustomData_get_layer_named_for_write(
|
||||
custom_data, eCustomDataType(layer.type), layer.name, element_num);
|
||||
custom_data,
|
||||
eCustomDataType(layer.type),
|
||||
layer.name,
|
||||
element_num,
|
||||
CustomDataUnsharePolicy_ArrayUnsharePolicy(unshare_policy));
|
||||
|
||||
const CPPType *type = custom_data_type_to_cpp_type(eCustomDataType(layer.type));
|
||||
if (type == nullptr) {
|
||||
|
@ -753,9 +769,10 @@ struct FinishCallChecker {
|
|||
};
|
||||
#endif
|
||||
|
||||
GAttributeWriter MutableAttributeAccessor::lookup_for_write(const AttributeIDRef &attribute_id)
|
||||
GAttributeWriter MutableAttributeAccessor::lookup_for_write(
|
||||
const AttributeIDRef &attribute_id, const ArrayUnsharePolicy &unshare_policy)
|
||||
{
|
||||
GAttributeWriter attribute = fn_->lookup_for_write(owner_, attribute_id);
|
||||
GAttributeWriter attribute = fn_->lookup_for_write(owner_, attribute_id, unshare_policy);
|
||||
/* Check that the #finish method is called in debug builds. */
|
||||
#ifndef NDEBUG
|
||||
if (attribute) {
|
||||
|
@ -774,9 +791,9 @@ GAttributeWriter MutableAttributeAccessor::lookup_for_write(const AttributeIDRef
|
|||
}
|
||||
|
||||
GSpanAttributeWriter MutableAttributeAccessor::lookup_for_write_span(
|
||||
const AttributeIDRef &attribute_id)
|
||||
const AttributeIDRef &attribute_id, const ArrayUnsharePolicy &unshare_policy)
|
||||
{
|
||||
GAttributeWriter attribute = this->lookup_for_write(attribute_id);
|
||||
GAttributeWriter attribute = this->lookup_for_write(attribute_id, unshare_policy);
|
||||
if (attribute) {
|
||||
return GSpanAttributeWriter{std::move(attribute), true};
|
||||
}
|
||||
|
@ -787,17 +804,18 @@ GAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write(
|
|||
const AttributeIDRef &attribute_id,
|
||||
const AttrDomain domain,
|
||||
const eCustomDataType data_type,
|
||||
const AttributeInit &initializer)
|
||||
const AttributeInit &initializer,
|
||||
const ArrayUnsharePolicy &unshare_policy)
|
||||
{
|
||||
std::optional<AttributeMetaData> meta_data = this->lookup_meta_data(attribute_id);
|
||||
if (meta_data.has_value()) {
|
||||
if (meta_data->domain == domain && meta_data->data_type == data_type) {
|
||||
return this->lookup_for_write(attribute_id);
|
||||
return this->lookup_for_write(attribute_id, unshare_policy);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
if (this->add(attribute_id, domain, data_type, initializer)) {
|
||||
return this->lookup_for_write(attribute_id);
|
||||
return this->lookup_for_write(attribute_id, unshare_policy);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -806,10 +824,11 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span(
|
|||
const AttributeIDRef &attribute_id,
|
||||
const AttrDomain domain,
|
||||
const eCustomDataType data_type,
|
||||
const AttributeInit &initializer)
|
||||
const AttributeInit &initializer,
|
||||
const ArrayUnsharePolicy &unshare_policy)
|
||||
{
|
||||
GAttributeWriter attribute = this->lookup_or_add_for_write(
|
||||
attribute_id, domain, data_type, initializer);
|
||||
attribute_id, domain, data_type, initializer, unshare_policy);
|
||||
if (attribute) {
|
||||
return GSpanAttributeWriter{std::move(attribute), true};
|
||||
}
|
||||
|
@ -820,7 +839,11 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span
|
|||
const AttributeIDRef &attribute_id, const AttrDomain domain, const eCustomDataType data_type)
|
||||
{
|
||||
GAttributeWriter attribute = this->lookup_or_add_for_write(
|
||||
attribute_id, domain, data_type, AttributeInitConstruct());
|
||||
attribute_id,
|
||||
domain,
|
||||
data_type,
|
||||
AttributeInitConstruct(),
|
||||
implicit_sharing::unshare::IgnoreOldValues());
|
||||
if (attribute) {
|
||||
return GSpanAttributeWriter{std::move(attribute), false};
|
||||
}
|
||||
|
|
|
@ -69,7 +69,8 @@ class BuiltinAttributeProvider {
|
|||
}
|
||||
|
||||
virtual GAttributeReader try_get_for_read(const void *owner) const = 0;
|
||||
virtual GAttributeWriter try_get_for_write(void *owner) const = 0;
|
||||
virtual GAttributeWriter try_get_for_write(void *owner,
|
||||
const ArrayUnsharePolicy &unshare_policy) const = 0;
|
||||
virtual bool try_delete(void *owner) const = 0;
|
||||
virtual bool try_create(void *onwer, const AttributeInit &initializer) const = 0;
|
||||
virtual bool exists(const void *owner) const = 0;
|
||||
|
@ -104,7 +105,8 @@ class DynamicAttributesProvider {
|
|||
virtual GAttributeReader try_get_for_read(const void *owner,
|
||||
const AttributeIDRef &attribute_id) const = 0;
|
||||
virtual GAttributeWriter try_get_for_write(void *owner,
|
||||
const AttributeIDRef &attribute_id) const = 0;
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy) const = 0;
|
||||
virtual bool try_delete(void *owner, const AttributeIDRef &attribute_id) const = 0;
|
||||
virtual bool try_create(void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
|
@ -141,7 +143,9 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
|||
GAttributeReader try_get_for_read(const void *owner,
|
||||
const AttributeIDRef &attribute_id) const final;
|
||||
|
||||
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final;
|
||||
GAttributeWriter try_get_for_write(void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy) const final;
|
||||
|
||||
bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final;
|
||||
|
||||
|
@ -199,7 +203,8 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
|
|||
}
|
||||
|
||||
GAttributeReader try_get_for_read(const void *owner) const final;
|
||||
GAttributeWriter try_get_for_write(void *owner) const final;
|
||||
GAttributeWriter try_get_for_write(void *owner,
|
||||
const ArrayUnsharePolicy &unshare_policy) const final;
|
||||
bool try_delete(void *owner) const final;
|
||||
bool try_create(void *owner, const AttributeInit &initializer) const final;
|
||||
bool exists(const void *owner) const final;
|
||||
|
@ -373,18 +378,20 @@ inline std::optional<AttributeMetaData> lookup_meta_data(const void *owner,
|
|||
}
|
||||
|
||||
template<const ComponentAttributeProviders &providers>
|
||||
inline GAttributeWriter lookup_for_write(void *owner, const AttributeIDRef &attribute_id)
|
||||
inline GAttributeWriter lookup_for_write(void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy &unshare_policy)
|
||||
{
|
||||
if (!attribute_id.is_anonymous()) {
|
||||
const StringRef name = attribute_id.name();
|
||||
if (const BuiltinAttributeProvider *provider =
|
||||
providers.builtin_attribute_providers().lookup_default_as(name, nullptr))
|
||||
{
|
||||
return provider->try_get_for_write(owner);
|
||||
return provider->try_get_for_write(owner, unshare_policy);
|
||||
}
|
||||
}
|
||||
for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
|
||||
GAttributeWriter attribute = provider->try_get_for_write(owner, attribute_id);
|
||||
GAttributeWriter attribute = provider->try_get_for_write(owner, attribute_id, unshare_policy);
|
||||
if (attribute) {
|
||||
return attribute;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BKE_anonymous_attribute_id.hh"
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_customdata_file.h"
|
||||
#include "BKE_deform.hh"
|
||||
|
@ -2377,6 +2378,27 @@ static void free_layer_data(const eCustomDataType type, const void *data, const
|
|||
MEM_freeN(const_cast<void *>(data));
|
||||
}
|
||||
|
||||
void CustomDataUnsharePolicy_CopyAll::unshare_data_impl(CustomDataLayer &layer,
|
||||
const int totelem) const
|
||||
{
|
||||
layer.data = copy_layer_data(eCustomDataType(layer.type), layer.data, totelem);
|
||||
}
|
||||
|
||||
void CustomDataUnsharePolicy_ArrayUnsharePolicy::unshare_data_impl(CustomDataLayer &layer,
|
||||
const int totelem) const
|
||||
{
|
||||
const eCustomDataType data_type = eCustomDataType(layer.type);
|
||||
const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
/* This unshare policy can't be used if there is no #CPPType for the layer type. */
|
||||
BLI_assert(type != nullptr);
|
||||
|
||||
void *new_data = MEM_mallocN_aligned(
|
||||
type->size() * int64_t(totelem), type->alignment(), __func__);
|
||||
array_unshare_policy_.unshare_array(blender::GVArray::ForSpan({type, layer.data, totelem}),
|
||||
blender::GMutableSpan{type, new_data, totelem});
|
||||
layer.data = new_data;
|
||||
}
|
||||
|
||||
static bool customdata_merge_internal(const CustomData *source,
|
||||
CustomData *dest,
|
||||
const eCustomDataMask mask,
|
||||
|
@ -2560,7 +2582,9 @@ static const ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCu
|
|||
/**
|
||||
* If the layer data is currently shared (hence it is immutable), create a copy that can be edited.
|
||||
*/
|
||||
static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totelem)
|
||||
static void ensure_layer_data_is_mutable(CustomDataLayer &layer,
|
||||
const int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
if (layer.data == nullptr) {
|
||||
return;
|
||||
|
@ -2574,10 +2598,9 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel
|
|||
}
|
||||
else {
|
||||
const eCustomDataType type = eCustomDataType(layer.type);
|
||||
const void *old_data = layer.data;
|
||||
/* Copy the layer before removing the user because otherwise the data might be freed while
|
||||
* we're still copying from it here. */
|
||||
layer.data = copy_layer_data(type, old_data, totelem);
|
||||
/* Unshare the layer data before removing the user because otherwise the data might be freed
|
||||
* while we're still copying from it here. */
|
||||
unshare_policy.unshare_data(layer, totelem);
|
||||
layer.sharing_info->remove_user_and_delete_if_last();
|
||||
layer.sharing_info = make_implicit_sharing_info_for_layer(type, layer.data, totelem);
|
||||
}
|
||||
|
@ -2591,15 +2614,19 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel
|
|||
return layer.sharing_info->is_mutable();
|
||||
}
|
||||
|
||||
void CustomData_ensure_data_is_mutable(CustomDataLayer *layer, const int totelem)
|
||||
void CustomData_ensure_data_is_mutable(CustomDataLayer *layer,
|
||||
const int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
ensure_layer_data_is_mutable(*layer, totelem);
|
||||
ensure_layer_data_is_mutable(*layer, totelem, unshare_policy);
|
||||
}
|
||||
|
||||
void CustomData_ensure_layers_are_mutable(CustomData *data, int totelem)
|
||||
void CustomData_ensure_layers_are_mutable(CustomData *data,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
for (const int i : IndexRange(data->totlayer)) {
|
||||
ensure_layer_data_is_mutable(data->layers[i], totelem);
|
||||
ensure_layer_data_is_mutable(data->layers[i], totelem, unshare_policy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3691,21 +3718,26 @@ void CustomData_swap_corners(CustomData *data, const int index, const int *corne
|
|||
void *CustomData_get_for_write(CustomData *data,
|
||||
const int index,
|
||||
const eCustomDataType type,
|
||||
int totelem)
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
void *layer_data = CustomData_get_layer_for_write(data, type, totelem);
|
||||
void *layer_data = CustomData_get_layer_for_write(data, type, totelem, unshare_policy);
|
||||
if (!layer_data) {
|
||||
return nullptr;
|
||||
}
|
||||
return POINTER_OFFSET(layer_data, size_t(index) * layerType_getInfo(type)->size);
|
||||
}
|
||||
|
||||
void *CustomData_get_n_for_write(
|
||||
CustomData *data, const eCustomDataType type, const int index, const int n, int totelem)
|
||||
void *CustomData_get_n_for_write(CustomData *data,
|
||||
const eCustomDataType type,
|
||||
const int index,
|
||||
const int n,
|
||||
int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
void *layer_data = CustomData_get_layer_n_for_write(data, type, n, totelem);
|
||||
void *layer_data = CustomData_get_layer_n_for_write(data, type, n, totelem, unshare_policy);
|
||||
if (!layer_data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3725,14 +3757,15 @@ const void *CustomData_get_layer(const CustomData *data, const eCustomDataType t
|
|||
|
||||
void *CustomData_get_layer_for_write(CustomData *data,
|
||||
const eCustomDataType type,
|
||||
const int totelem)
|
||||
const int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
const int layer_index = CustomData_get_active_layer_index(data, type);
|
||||
if (layer_index == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
CustomDataLayer &layer = data->layers[layer_index];
|
||||
ensure_layer_data_is_mutable(layer, totelem);
|
||||
ensure_layer_data_is_mutable(layer, totelem, unshare_policy);
|
||||
return layer.data;
|
||||
}
|
||||
|
||||
|
@ -3748,14 +3781,15 @@ const void *CustomData_get_layer_n(const CustomData *data, const eCustomDataType
|
|||
void *CustomData_get_layer_n_for_write(CustomData *data,
|
||||
const eCustomDataType type,
|
||||
const int n,
|
||||
const int totelem)
|
||||
const int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
const int layer_index = CustomData_get_layer_index_n(data, type, n);
|
||||
if (layer_index == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
CustomDataLayer &layer = data->layers[layer_index];
|
||||
ensure_layer_data_is_mutable(layer, totelem);
|
||||
ensure_layer_data_is_mutable(layer, totelem, unshare_policy);
|
||||
return layer.data;
|
||||
}
|
||||
|
||||
|
@ -3773,14 +3807,15 @@ const void *CustomData_get_layer_named(const CustomData *data,
|
|||
void *CustomData_get_layer_named_for_write(CustomData *data,
|
||||
const eCustomDataType type,
|
||||
const StringRef name,
|
||||
const int totelem)
|
||||
const int totelem,
|
||||
const CustomDataUnsharePolicy &unshare_policy)
|
||||
{
|
||||
const int layer_index = CustomData_get_named_layer_index(data, type, name);
|
||||
if (layer_index == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
CustomDataLayer &layer = data->layers[layer_index];
|
||||
ensure_layer_data_is_mutable(layer, totelem);
|
||||
ensure_layer_data_is_mutable(layer, totelem, unshare_policy);
|
||||
return layer.data;
|
||||
}
|
||||
|
||||
|
|
|
@ -372,7 +372,9 @@ class CurvesVertexGroupsAttributeProvider final : public DynamicAttributesProvid
|
|||
return {varray_for_deform_verts(dverts, vertex_group_index), AttrDomain::Point};
|
||||
}
|
||||
|
||||
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
|
||||
GAttributeWriter try_get_for_write(void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy & /*unshare_policy*/) const final
|
||||
{
|
||||
if (attribute_id.is_anonymous()) {
|
||||
return {};
|
||||
|
|
|
@ -900,7 +900,9 @@ class MeshVertexGroupsAttributeProvider final : public DynamicAttributesProvider
|
|||
return {varray_for_deform_verts(dverts, vertex_group_index), AttrDomain::Point};
|
||||
}
|
||||
|
||||
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
|
||||
GAttributeWriter try_get_for_write(void *owner,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const ArrayUnsharePolicy & /*unshare_policy*/) const final
|
||||
{
|
||||
if (attribute_id.is_anonymous()) {
|
||||
return {};
|
||||
|
|
|
@ -609,10 +609,15 @@ Span<float3> Mesh::vert_positions() const
|
|||
CustomData_get_layer_named(&this->vert_data, CD_PROP_FLOAT3, "position")),
|
||||
this->verts_num};
|
||||
}
|
||||
MutableSpan<float3> Mesh::vert_positions_for_write()
|
||||
MutableSpan<float3> Mesh::vert_positions_for_write(
|
||||
const blender::ArrayUnsharePolicy &unshare_policy)
|
||||
{
|
||||
return {static_cast<float3 *>(CustomData_get_layer_named_for_write(
|
||||
&this->vert_data, CD_PROP_FLOAT3, "position", this->verts_num)),
|
||||
&this->vert_data,
|
||||
CD_PROP_FLOAT3,
|
||||
"position",
|
||||
this->verts_num,
|
||||
CustomDataUnsharePolicy_ArrayUnsharePolicy(unshare_policy))),
|
||||
this->verts_num};
|
||||
}
|
||||
|
||||
|
|
|
@ -209,10 +209,15 @@ Span<float3> PointCloud::positions() const
|
|||
this->totpoint};
|
||||
}
|
||||
|
||||
MutableSpan<float3> PointCloud::positions_for_write()
|
||||
MutableSpan<float3> PointCloud::positions_for_write(
|
||||
const blender::ArrayUnsharePolicy &unshare_policy)
|
||||
{
|
||||
return {static_cast<float3 *>(CustomData_get_layer_named_for_write(
|
||||
&this->pdata, CD_PROP_FLOAT3, "position", this->totpoint)),
|
||||
&this->pdata,
|
||||
CD_PROP_FLOAT3,
|
||||
"position",
|
||||
this->totpoint,
|
||||
CustomDataUnsharePolicy_ArrayUnsharePolicy(unshare_policy))),
|
||||
this->totpoint};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_generic_virtual_array.hh"
|
||||
|
||||
namespace blender::implicit_sharing::unshare {
|
||||
|
||||
class ArrayUnsharePolicy {
|
||||
public:
|
||||
void unshare_array(const GVArray &src, GMutableSpan dst) const
|
||||
{
|
||||
BLI_assert(src.type() == dst.type());
|
||||
BLI_assert(src.size() == dst.size());
|
||||
this->unshare_array_impl(src, dst);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void unshare_array_impl(const GVArray &src, GMutableSpan dst) const = 0;
|
||||
};
|
||||
|
||||
class CopyAll : public ArrayUnsharePolicy {
|
||||
virtual void unshare_array_impl(const GVArray &src, GMutableSpan dst) const override
|
||||
{
|
||||
src.materialize_to_uninitialized(dst.data());
|
||||
}
|
||||
};
|
||||
|
||||
class IgnoreOldValues : public ArrayUnsharePolicy {
|
||||
void unshare_array_impl(const GVArray & /*src*/, GMutableSpan dst) const override
|
||||
{
|
||||
const CPPType &type = dst.type();
|
||||
type.default_construct_n(dst.data(), dst.size());
|
||||
}
|
||||
};
|
||||
|
||||
using DefaultArrayUnsharePolicy = CopyAll;
|
||||
|
||||
} // namespace blender::implicit_sharing::unshare
|
||||
|
||||
namespace blender {
|
||||
using implicit_sharing::unshare::ArrayUnsharePolicy;
|
||||
using implicit_sharing::unshare::DefaultArrayUnsharePolicy;
|
||||
} // namespace blender
|
|
@ -251,6 +251,7 @@ set(SRC
|
|||
BLI_implicit_sharing.h
|
||||
BLI_implicit_sharing.hh
|
||||
BLI_implicit_sharing_ptr.hh
|
||||
BLI_implicit_sharing_unshare.hh
|
||||
BLI_index_mask.hh
|
||||
BLI_index_mask_fwd.hh
|
||||
BLI_index_mask_expression.hh
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
# include <optional>
|
||||
|
||||
# include "BLI_implicit_sharing_unshare.hh"
|
||||
# include "BLI_math_vector_types.hh"
|
||||
|
||||
namespace blender {
|
||||
|
@ -236,7 +237,8 @@ typedef struct Mesh {
|
|||
*/
|
||||
blender::Span<blender::float3> vert_positions() const;
|
||||
/** Write access to vertex data. */
|
||||
blender::MutableSpan<blender::float3> vert_positions_for_write();
|
||||
blender::MutableSpan<blender::float3> vert_positions_for_write(
|
||||
const blender::ArrayUnsharePolicy &unshare_policy = blender::DefaultArrayUnsharePolicy());
|
||||
/**
|
||||
* Array of edges, containing vertex indices, stored in the ".edge_verts" attribute. For simple
|
||||
* triangle or quad meshes, edges could be calculated from the face and #corner_edge arrays.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# include <optional>
|
||||
|
||||
# include "BLI_bounds_types.hh"
|
||||
# include "BLI_implicit_sharing_unshare.hh"
|
||||
# include "BLI_math_vector_types.hh"
|
||||
# include "BLI_span.hh"
|
||||
#endif
|
||||
|
@ -54,7 +55,8 @@ typedef struct PointCloud {
|
|||
|
||||
#ifdef __cplusplus
|
||||
blender::Span<blender::float3> positions() const;
|
||||
blender::MutableSpan<blender::float3> positions_for_write();
|
||||
blender::MutableSpan<blender::float3> positions_for_write(
|
||||
const blender::ArrayUnsharePolicy &unshare_policy = blender::DefaultArrayUnsharePolicy());
|
||||
|
||||
blender::bke::AttributeAccessor attributes() const;
|
||||
blender::bke::MutableAttributeAccessor attributes_for_write();
|
||||
|
|
Loading…
Reference in New Issue