Geometry Nodes: Optimize joining of instances

Restore lost performance from removing `reserve` in ff4d5b6f04
in a better way. First build offsets so we know where in the result the
source data should go, then copy the data in parallel.

Joining geometries containing 1 million instances each took 194 ms
before the change and only 15.6 ms afterwards.

Pull Request: https://projects.blender.org/blender/blender/pulls/113886
This commit is contained in:
Hans Goudey
2023-10-19 10:23:59 +02:00
committed by Hans Goudey
parent 564c25291f
commit a5eaf6698a

View File

@@ -2,6 +2,8 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array_utils.hh"
#include "GEO_join_geometries.hh"
#include "GEO_realize_instances.hh"
@@ -97,19 +99,22 @@ static void join_attributes(const Span<const GeometryComponent *> src_components
static void join_instances(const Span<const GeometryComponent *> src_components,
GeometrySet &result)
{
std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
int tot_instances = 0;
for (const GeometryComponent *src_component : src_components) {
const bke::InstancesComponent &src_instance_component =
static_cast<const bke::InstancesComponent &>(*src_component);
tot_instances += src_instance_component.get()->instances_num();
Array<int> offsets_data(src_components.size() + 1);
for (const int i : src_components.index_range()) {
const auto &src_component = static_cast<const bke::InstancesComponent &>(*src_components[i]);
offsets_data[i] = src_component.get()->instances_num();
}
const OffsetIndices offsets = offset_indices::accumulate_counts_to_offsets(offsets_data);
for (const GeometryComponent *src_component : src_components) {
const bke::InstancesComponent &src_instance_component =
static_cast<const bke::InstancesComponent &>(*src_component);
const bke::Instances &src_instances = *src_instance_component.get();
std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
dst_instances->resize(offsets.total_size());
MutableSpan<float4x4> all_transforms = dst_instances->transforms();
MutableSpan<int> all_handles = dst_instances->reference_handles();
for (const int i : src_components.index_range()) {
const auto &src_component = static_cast<const bke::InstancesComponent &>(*src_components[i]);
const bke::Instances &src_instances = *src_component.get();
const Span<bke::InstanceReference> src_references = src_instances.references();
Array<int> handle_map(src_references.size());
@@ -117,20 +122,15 @@ static void join_instances(const Span<const GeometryComponent *> src_components,
handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
}
const Span<float4x4> src_transforms = src_instances.transforms();
const Span<int> src_reference_handles = src_instances.reference_handles();
const IndexRange dst_range = offsets[i];
for (const int i : src_transforms.index_range()) {
const int src_handle = src_reference_handles[i];
const int dst_handle = handle_map[src_handle];
const float4x4 &transform = src_transforms[i];
dst_instances->add_instance(dst_handle, transform);
}
const Span<int> src_handles = src_instances.reference_handles();
array_utils::gather(handle_map.as_span(), src_handles, all_handles.slice(dst_range));
array_utils::copy(src_instances.transforms(), all_transforms.slice(dst_range));
}
result.replace_instances(dst_instances.release());
bke::InstancesComponent &dst_component =
result.get_component_for_write<bke::InstancesComponent>();
auto &dst_component = result.get_component_for_write<bke::InstancesComponent>();
join_attributes(src_components, dst_component, {"position"});
}