Geometry Nodes: don't use CustomDataAttributes in Instances
This was the last use of `CustomDataAttributes`. It's not very useful nowadays because we have a lower level (`CustomData`) and higher level (`AttributeAccessor`) API. As part of this I removed the ability to `reserve` instances which was useful when adding instances one by one. Generally, such code should eventually be rewritten to handle more instances at once, instead of handling them one by one. This will lead to better performance and is more in line with how other geometry types (like mesh) are handled. This also adds the ability to move and assign `Instances` just like we can move and assign `CurvesGeometry`.
This commit is contained in:
@@ -197,7 +197,10 @@ bool CustomData_merge_layout(const struct CustomData *source,
|
||||
* the #CD_CONSTRUCT behavior, so trivial types must be initialized by the caller. After being
|
||||
* resized, the #CustomData does not contain any referenced layers.
|
||||
*/
|
||||
void CustomData_realloc(struct CustomData *data, int old_size, int new_size);
|
||||
void CustomData_realloc(struct CustomData *data,
|
||||
int old_size,
|
||||
int new_size,
|
||||
eCDAllocType alloctype = CD_CONSTRUCT);
|
||||
|
||||
/**
|
||||
* BMesh version of CustomData_merge_layout; merges the layouts of source and `dest`,
|
||||
|
||||
@@ -102,13 +102,17 @@ class Instances {
|
||||
mutable std::mutex almost_unique_ids_mutex_;
|
||||
mutable blender::Array<int> almost_unique_ids_;
|
||||
|
||||
CustomDataAttributes attributes_;
|
||||
CustomData attributes_;
|
||||
|
||||
public:
|
||||
Instances() = default;
|
||||
Instances();
|
||||
Instances(Instances &&other);
|
||||
Instances(const Instances &other);
|
||||
~Instances();
|
||||
|
||||
Instances &operator=(const Instances &other);
|
||||
Instances &operator=(Instances &&other);
|
||||
|
||||
void reserve(int min_capacity);
|
||||
/**
|
||||
* Resize the transform, handles, and attributes to the specified capacity.
|
||||
*
|
||||
@@ -258,12 +262,12 @@ inline const GeometrySet &InstanceReference::geometry_set() const
|
||||
|
||||
inline CustomData &Instances::custom_data_attributes()
|
||||
{
|
||||
return attributes_.data;
|
||||
return attributes_;
|
||||
}
|
||||
|
||||
inline const CustomData &Instances::custom_data_attributes() const
|
||||
{
|
||||
return attributes_.data;
|
||||
return attributes_;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -2434,7 +2434,10 @@ void CustomData_ensure_layers_are_mutable(struct CustomData *data, int totelem)
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_realloc(CustomData *data, const int old_size, const int new_size)
|
||||
void CustomData_realloc(CustomData *data,
|
||||
const int old_size,
|
||||
const int new_size,
|
||||
const eCDAllocType alloctype)
|
||||
{
|
||||
BLI_assert(new_size >= 0);
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
@@ -2467,10 +2470,25 @@ void CustomData_realloc(CustomData *data, const int old_size, const int new_size
|
||||
}
|
||||
|
||||
if (new_size > old_size) {
|
||||
/* Initialize new values for non-trivial types. */
|
||||
if (typeInfo->construct) {
|
||||
const int new_elements_num = new_size - old_size;
|
||||
typeInfo->construct(POINTER_OFFSET(layer->data, old_size_in_bytes), new_elements_num);
|
||||
const int new_elements_num = new_size - old_size;
|
||||
void *new_elements_begin = POINTER_OFFSET(layer->data, old_size_in_bytes);
|
||||
switch (alloctype) {
|
||||
case CD_CONSTRUCT: {
|
||||
/* Initialize new values for non-trivial types. */
|
||||
if (typeInfo->construct) {
|
||||
typeInfo->construct(new_elements_begin, new_elements_num);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CD_SET_DEFAULT: {
|
||||
if (typeInfo->set_default_value) {
|
||||
typeInfo->set_default_value(new_elements_begin, new_elements_num);
|
||||
}
|
||||
else {
|
||||
memset(new_elements_begin, 0, typeInfo->size * new_elements_num);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,36 +43,71 @@ bool operator==(const InstanceReference &a, const InstanceReference &b)
|
||||
return a.type_ == b.type_ && a.data_ == b.data_;
|
||||
}
|
||||
|
||||
Instances::Instances()
|
||||
{
|
||||
CustomData_reset(&attributes_);
|
||||
}
|
||||
|
||||
Instances::Instances(Instances &&other)
|
||||
: references_(std::move(other.references_)),
|
||||
reference_handles_(std::move(other.reference_handles_)),
|
||||
transforms_(std::move(other.transforms_)),
|
||||
almost_unique_ids_(std::move(other.almost_unique_ids_)),
|
||||
attributes_(other.attributes_)
|
||||
{
|
||||
CustomData_reset(&other.attributes_);
|
||||
}
|
||||
|
||||
Instances::Instances(const Instances &other)
|
||||
: references_(other.references_),
|
||||
reference_handles_(other.reference_handles_),
|
||||
transforms_(other.transforms_),
|
||||
almost_unique_ids_(other.almost_unique_ids_),
|
||||
attributes_(other.attributes_)
|
||||
almost_unique_ids_(other.almost_unique_ids_)
|
||||
{
|
||||
CustomData_copy(&other.attributes_, &attributes_, CD_MASK_ALL, other.instances_num());
|
||||
}
|
||||
|
||||
void Instances::reserve(int min_capacity)
|
||||
Instances::~Instances()
|
||||
{
|
||||
reference_handles_.reserve(min_capacity);
|
||||
transforms_.reserve(min_capacity);
|
||||
attributes_.reallocate(min_capacity);
|
||||
CustomData_free(&attributes_, this->instances_num());
|
||||
}
|
||||
|
||||
Instances &Instances::operator=(const Instances &other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
std::destroy_at(this);
|
||||
new (this) Instances(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Instances &Instances::operator=(Instances &&other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
std::destroy_at(this);
|
||||
new (this) Instances(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Instances::resize(int capacity)
|
||||
{
|
||||
const int old_size = this->instances_num();
|
||||
reference_handles_.resize(capacity);
|
||||
transforms_.resize(capacity);
|
||||
attributes_.reallocate(capacity);
|
||||
CustomData_realloc(&attributes_, old_size, capacity, CD_SET_DEFAULT);
|
||||
}
|
||||
|
||||
void Instances::add_instance(const int instance_handle, const float4x4 &transform)
|
||||
{
|
||||
BLI_assert(instance_handle >= 0);
|
||||
BLI_assert(instance_handle < references_.size());
|
||||
const int old_size = this->instances_num();
|
||||
reference_handles_.append(instance_handle);
|
||||
transforms_.append(transform);
|
||||
attributes_.reallocate(this->instances_num());
|
||||
CustomData_realloc(&attributes_, old_size, transforms_.size());
|
||||
}
|
||||
|
||||
Span<int> Instances::reference_handles() const
|
||||
@@ -138,37 +173,25 @@ void Instances::remove(const IndexMask &mask,
|
||||
return;
|
||||
}
|
||||
|
||||
const Span<int> old_handles = this->reference_handles();
|
||||
Vector<int> new_handles(mask.size());
|
||||
array_utils::gather(old_handles, mask, new_handles.as_mutable_span());
|
||||
reference_handles_ = std::move(new_handles);
|
||||
const int new_size = mask.size();
|
||||
|
||||
const Span<float4x4> old_tansforms = this->transforms();
|
||||
Vector<float4x4> new_transforms(mask.size());
|
||||
array_utils::gather(old_tansforms, mask, new_transforms.as_mutable_span());
|
||||
transforms_ = std::move(new_transforms);
|
||||
Instances new_instances;
|
||||
new_instances.references_ = std::move(references_);
|
||||
new_instances.reference_handles_.resize(new_size);
|
||||
new_instances.transforms_.resize(new_size);
|
||||
array_utils::gather(
|
||||
reference_handles_.as_span(), mask, new_instances.reference_handles_.as_mutable_span());
|
||||
array_utils::gather(transforms_.as_span(), mask, new_instances.transforms_.as_mutable_span());
|
||||
|
||||
const bke::CustomDataAttributes &src_attributes = attributes_;
|
||||
gather_attributes(this->attributes(),
|
||||
ATTR_DOMAIN_INSTANCE,
|
||||
propagation_info,
|
||||
{"position"},
|
||||
mask,
|
||||
new_instances.attributes_for_write());
|
||||
|
||||
bke::CustomDataAttributes dst_attributes;
|
||||
dst_attributes.reallocate(mask.size());
|
||||
*this = std::move(new_instances);
|
||||
|
||||
src_attributes.foreach_attribute(
|
||||
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
|
||||
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
GSpan src = *src_attributes.get_for_read(id);
|
||||
dst_attributes.create(id, meta_data.data_type);
|
||||
GMutableSpan dst = *dst_attributes.get_for_write(id);
|
||||
array_utils::gather(src, mask, dst);
|
||||
|
||||
return true;
|
||||
},
|
||||
ATTR_DOMAIN_INSTANCE);
|
||||
|
||||
attributes_ = std::move(dst_attributes);
|
||||
this->remove_unused_references();
|
||||
}
|
||||
|
||||
@@ -334,9 +357,9 @@ static Array<int> generate_unique_instance_ids(Span<int> original_ids)
|
||||
Span<int> Instances::almost_unique_ids() const
|
||||
{
|
||||
std::lock_guard lock(almost_unique_ids_mutex_);
|
||||
std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
|
||||
if (instance_ids_gspan) {
|
||||
Span<int> instance_ids = instance_ids_gspan->typed<int>();
|
||||
bke::AttributeReader<int> instance_ids_attribute = this->attributes().lookup<int>("id");
|
||||
if (instance_ids_attribute) {
|
||||
Span<int> instance_ids = instance_ids_attribute.varray.get_internal_span();
|
||||
if (almost_unique_ids_.size() != instance_ids.size()) {
|
||||
almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,6 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
|
||||
static_cast<const bke::InstancesComponent &>(*src_component);
|
||||
tot_instances += src_instance_component.get()->instances_num();
|
||||
}
|
||||
dst_instances->reserve(tot_instances);
|
||||
|
||||
for (const GeometryComponent *src_component : src_components) {
|
||||
const bke::InstancesComponent &src_instance_component =
|
||||
|
||||
@@ -32,7 +32,6 @@ using blender::bke::AttributeIDRef;
|
||||
using blender::bke::AttributeKind;
|
||||
using blender::bke::AttributeMetaData;
|
||||
using blender::bke::custom_data_type_to_cpp_type;
|
||||
using blender::bke::CustomDataAttributes;
|
||||
using blender::bke::GSpanAttributeWriter;
|
||||
using blender::bke::InstanceReference;
|
||||
using blender::bke::Instances;
|
||||
|
||||
@@ -89,7 +89,6 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
children_objects.append(collection_object->ob);
|
||||
}
|
||||
|
||||
instances->reserve(children_collections.size() + children_objects.size());
|
||||
Vector<InstanceListEntry> entries;
|
||||
entries.reserve(children_collections.size() + children_objects.size());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user