Geometry Nodes: Improve performance of mesh to points node

There are fancier possibilities for improvements, like taking ownership
of existing arrays in some cases, but this patch takes a simpler brute
force approach for now.

The first change is to move from the previous loop to using the new
`materialize_compressed_to_uninitialized` method on virtual arrays,
which adds only the selected values to the output. That is a nice
improvement in some cases, corresponding to the "Without Threading"
column in the chart below.

The next change is to call that function in parallel on slices of
the output. To avoid generating too much code, we can avoid
templating based on the type and devirtualizing completely.

The test input is a 4 million point grid, generated by the grid
primitive node. Color and 2D vector attributes were also transferred
to the points.

| Test      | Before | Final No Threading | Final  | Change |
| --------- | ------ | ------------------ | ------ | ------ |
| All Verts | 209 ms | 186 ms             | 170 ms | 0.8x   |
| 1%        | 148 ms | 143 ms             | 133 ms | 0.9x   |
| All Faces | 326 ms | 303 ms             | 87 ms  | 0.27x  |
| 1%  Faces | 70 ms  | 68 ms              | 34 ms  | 0.49x  |

Differential Revision: https://developer.blender.org/D14661
This commit is contained in:
Hans Goudey 2022-05-05 09:26:08 +02:00
parent 0f567ada9d
commit 6513ce258f
1 changed files with 22 additions and 18 deletions

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_task.hh"
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
@ -41,14 +43,15 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
template<typename T>
static void copy_attribute_to_points(const VArray<T> &src,
const IndexMask mask,
MutableSpan<T> dst)
static void materialize_compressed_to_uninitialized_threaded(const GVArray &src,
const IndexMask mask,
GMutableSpan dst)
{
for (const int i : mask.index_range()) {
dst[i] = src[mask[i]];
}
BLI_assert(src.type() == dst.type());
BLI_assert(mask.size() == dst.size());
threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
src.materialize_compressed_to_uninitialized(mask.slice(range), dst.slice(range).data());
});
}
static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
@ -79,16 +82,21 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
geometry_set.replace_pointcloud(pointcloud);
PointCloudComponent &point_component =
geometry_set.get_component_for_write<PointCloudComponent>();
copy_attribute_to_points(evaluator.get_evaluated<float3>(0),
selection,
{(float3 *)pointcloud->co, pointcloud->totpoint});
copy_attribute_to_points(
evaluator.get_evaluated<float>(1), selection, {pointcloud->radius, pointcloud->totpoint});
OutputAttribute position = point_component.attribute_try_get_for_output_only(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
materialize_compressed_to_uninitialized_threaded(
evaluator.get_evaluated(0), selection, position.as_span());
position.save();
OutputAttribute radius = point_component.attribute_try_get_for_output_only(
"radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
materialize_compressed_to_uninitialized_threaded(
evaluator.get_evaluated(1), selection, radius.as_span());
radius.save();
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
@ -102,11 +110,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
OutputAttribute dst = point_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArray<T> src_typed = src.typed<T>();
copy_attribute_to_points(src_typed, selection, dst.as_span().typed<T>());
});
materialize_compressed_to_uninitialized_threaded(src, selection, dst.as_span());
dst.save();
}
}