Geometry Nodes: optimize Sample Index node with constant index

Previously, the node would always evaluate the input field on the
entire geometry domain. This is good when most indices will be
accessed afterwards. However, it is quite a bad when only a single
index is used. Now the field is only evaluated for that one index.
This commit is contained in:
Jacques Lucke 2023-01-17 13:29:55 +01:00
parent 03fab057f1
commit b510508513
Notes: blender-bot 2023-02-14 08:06:38 +01:00
Referenced by commit 34326fec02, Fix: sample index node outputs default value
1 changed files with 33 additions and 6 deletions

View File

@ -299,12 +299,39 @@ static void node_geo_exec(GeoNodeExecParams params)
const eCustomDataType data_type = eCustomDataType(storage.data_type);
const eAttrDomain domain = eAttrDomain(storage.domain);
auto fn = std::make_shared<SampleIndexFunction>(std::move(geometry),
get_input_attribute_field(params, data_type),
domain,
bool(storage.clamp));
auto op = FieldOperation::Create(std::move(fn), {params.extract_input<Field<int>>("Index")});
output_attribute_field(params, GField(std::move(op)));
GField value_field = get_input_attribute_field(params, data_type);
ValueOrField<int> index_value_or_field = params.extract_input<ValueOrField<int>>("Index");
const CPPType &cpp_type = value_field.cpp_type();
GField output_field;
if (index_value_or_field.is_field()) {
/* If the index is a field, the output has to be a field that still depends on the input. */
auto fn = std::make_shared<SampleIndexFunction>(
std::move(geometry), std::move(value_field), domain, bool(storage.clamp));
auto op = FieldOperation::Create(std::move(fn), {index_value_or_field.as_field()});
output_field = GField(std::move(op));
}
else if (const GeometryComponent *component = find_source_component(geometry, domain)) {
/* Optimization for the case when the index is a single value. Here only that one index has to
* be evaluated. */
const int index = index_value_or_field.as_value();
const IndexMask mask = IndexRange(index, 1);
bke::GeometryFieldContext geometry_context(*component, domain);
FieldEvaluator evaluator(geometry_context, &mask);
evaluator.add(value_field);
evaluator.evaluate();
const GVArray &data = evaluator.get_evaluated(0);
BUFFER_FOR_CPP_TYPE_VALUE(cpp_type, buffer);
data.get_to_uninitialized(index, buffer);
output_field = fn::make_constant_field(cpp_type, cpp_type.default_value());
cpp_type.destruct(buffer);
}
else {
/* Output default value if there is no geometry. */
output_field = fn::make_constant_field(cpp_type, cpp_type.default_value());
}
output_attribute_field(params, std::move(output_field));
}
} // namespace blender::nodes::node_geo_sample_index_cc