BLI: refactor IndexMask for better performance and memory usage #104629

Merged
Jacques Lucke merged 254 commits from JacquesLucke/blender:index-mask-refactor into main 2023-05-24 18:11:47 +02:00
17 changed files with 63 additions and 69 deletions
Showing only changes of commit 1d23e61bad - Show all commits

View File

@ -274,7 +274,7 @@ void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType
}
}
/* A potential performance optimization is only counting the changed indices. */
this->curve_types_for_write().fill_indices(selection, type);
index_mask::masked_fill<int8_t>(this->curve_types_for_write(), type, selection);
this->update_curve_types();
this->tag_topology_changed();
}
@ -581,9 +581,9 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
const VArray<int8_t> orders = this->nurbs_orders();
const VArray<int8_t> knots_modes = this->nurbs_knots_modes();
threading::parallel_for(nurbs_mask.index_range(), 64, [&](const IndexRange range) {
nurbs_mask.foreach_span(GrainSize(64), [&](const auto sliced_mask) {
Vector<float, 32> knots;
for (const int curve_index : nurbs_mask.slice(range)) {
for (const int curve_index : sliced_mask) {
const IndexRange points = points_by_curve[curve_index];
const IndexRange evaluated_points = evaluated_points_by_curve[curve_index];
@ -1222,7 +1222,7 @@ static CurvesGeometry copy_with_removed_curves(
const OffsetIndices old_points_by_curve = curves.points_by_curve();
const Span<int> old_offsets = curves.offsets();
const Vector<IndexRange> old_curve_ranges = curves_to_delete.to_ranges_invert(
curves.curves_range(), nullptr);
curves.curves_range());
Vector<IndexRange> new_curve_ranges;
Vector<IndexRange> old_point_ranges;
Vector<IndexRange> new_point_ranges;
@ -1338,10 +1338,8 @@ static void reverse_curve_point_data(const CurvesGeometry &curves,
MutableSpan<T> data)
{
const OffsetIndices points_by_curve = curves.points_by_curve();
threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) {
for (const int curve_i : curve_selection.slice(range)) {
data.slice(points_by_curve[curve_i]).reverse();
}
curve_selection.foreach_index([&](const int curve_i) {
data.slice(points_by_curve[curve_i]).reverse();
});
}
@ -1352,20 +1350,18 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves,
MutableSpan<T> data_b)
{
const OffsetIndices points_by_curve = curves.points_by_curve();
threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) {
for (const int curve_i : curve_selection.slice(range)) {
const IndexRange points = points_by_curve[curve_i];
MutableSpan<T> a = data_a.slice(points);
MutableSpan<T> b = data_b.slice(points);
for (const int i : IndexRange(points.size() / 2)) {
const int end_index = points.size() - 1 - i;
std::swap(a[end_index], b[i]);
std::swap(b[end_index], a[i]);
}
if (points.size() % 2) {
const int64_t middle_index = points.size() / 2;
std::swap(a[middle_index], b[middle_index]);
}
curve_selection.foreach_index(GrainSize(256), [&](const int curve_i) {
const IndexRange points = points_by_curve[curve_i];
MutableSpan<T> a = data_a.slice(points);
MutableSpan<T> b = data_b.slice(points);
for (const int i : IndexRange(points.size() / 2)) {
const int end_index = points.size() - 1 - i;
std::swap(a[end_index], b[i]);
std::swap(b[end_index], a[i]);
}
if (points.size() % 2) {
const int64_t middle_index = points.size() / 2;
std::swap(a[middle_index], b[middle_index]);
}
});
}

View File

@ -137,11 +137,11 @@ VArray<float3> mesh_normals_varray(const Mesh &mesh,
Span<float3> vert_normals = mesh.vert_normals();
const Span<MEdge> edges = mesh.edges();
Array<float3> edge_normals(mask.min_array_size());
for (const int i : mask) {
mask.foreach_index([&](const int i) {
const MEdge &edge = edges[i];
edge_normals[i] = math::normalize(
math::interpolate(vert_normals[edge.v1], vert_normals[edge.v2], 0.5f));
}
});
return VArray<float3>::ForContainer(std::move(edge_normals));
}
@ -980,14 +980,12 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
if (dverts_ == nullptr) {
mask.foreach_index([&](const int i) { dst[i] = 0.0f; });
}
threading::parallel_for(mask.index_range(), 4096, [&](const IndexRange range) {
for (const int64_t i : mask.slice(range)) {
if (const MDeformWeight *weight = this->find_weight_at_index(i)) {
dst[i] = weight->weight;
}
else {
dst[i] = 0.0f;
}
mask.foreach_index(GrainSize(4096), [&](const int64_t i) {
if (const MDeformWeight *weight = this->find_weight_at_index(i)) {
dst[i] = weight->weight;
}
else {
dst[i] = 0.0f;
}
});
}

View File

@ -109,7 +109,8 @@ void Instances::remove(const IndexMask mask,
const AnonymousAttributePropagationInfo &propagation_info)
{
using namespace blender;
if (mask.is_range() && mask.as_range().start() == 0) {
const std::optional<IndexRange> masked_range = mask.to_range();
if (masked_range.has_value() && masked_range->start() == 0) {
/* Deleting from the end of the array can be much faster since no data has to be shifted. */
this->resize(mask.size());
this->remove_unused_references();
@ -118,12 +119,12 @@ void Instances::remove(const IndexMask mask,
const Span<int> old_handles = this->reference_handles();
Vector<int> new_handles(mask.size());
array_utils::gather(old_handles, mask.indices(), new_handles.as_mutable_span());
array_utils::gather(old_handles, mask, new_handles.as_mutable_span());
reference_handles_ = std::move(new_handles);
const Span<float4x4> old_tansforms = this->transforms();
Vector<float4x4> new_transforms(mask.size());
array_utils::gather(old_tansforms, mask.indices(), new_transforms.as_mutable_span());
array_utils::gather(old_tansforms, mask, new_transforms.as_mutable_span());
transforms_ = std::move(new_transforms);
const bke::CustomDataAttributes &src_attributes = attributes_;
@ -140,7 +141,7 @@ void Instances::remove(const IndexMask mask,
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.indices(), dst);
array_utils::gather(src, mask, dst);
return true;
},

View File

@ -24,7 +24,7 @@ BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
const Span<MLoop> loops = mesh.loops();
const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
mask.foreach_index([&](const int i) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
@ -39,7 +39,7 @@ BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
dst[i] = interpolated_value;
}
});
}
void sample_point_attribute(const Mesh &mesh,
@ -70,7 +70,7 @@ BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
{
const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
mask.foreach_index([&](const int i) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
@ -85,7 +85,7 @@ BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
dst[i] = interpolated_value;
}
});
}
void sample_corner_attribute(const Mesh &mesh,
@ -115,12 +115,12 @@ void sample_face_attribute(const Mesh &mesh,
{
const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
mask.foreach_index([&](const int i) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const int poly_index = looptri.poly;
dst[i] = src[poly_index];
}
});
}
void sample_face_attribute(const Mesh &mesh,
@ -160,7 +160,7 @@ Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
const Span<MLoop> loops = mesh_->loops();
const Span<MLoopTri> looptris = mesh_->looptris();
for (const int i : mask_) {
mask_.foreach_index([&](const int i) {
const int looptri_index = looptri_indices_[i];
const MLoopTri &looptri = looptris[looptri_index];
@ -173,7 +173,7 @@ Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
positions[v1_index],
positions[v2_index],
positions_[i]);
}
});
return bary_coords_;
}
@ -189,7 +189,7 @@ Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
const Span<MLoop> loops = mesh_->loops();
const Span<MLoopTri> looptris = mesh_->looptris();
for (const int i : mask_) {
mask_.foreach_index([&](const int i) {
const int looptri_index = looptri_indices_[i];
const MLoopTri &looptri = looptris[looptri_index];
@ -202,7 +202,7 @@ Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
const float d2 = len_squared_v3v3(positions_[i], positions[v2_index]);
nearest_weights_[i] = MIN3_PAIR(d0, d1, d2, float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1));
}
});
return nearest_weights_;
}

View File

@ -406,7 +406,6 @@ IndexMask IndexMask::slice_and_offset(const int64_t start,
IndexMask IndexMask::complement(const IndexRange universe, IndexMaskMemory &memory) const
{
IndexMaskMemory memory;
const AtomicExpr atomic_expr{*this};
const ComplementExpr complement_expr{atomic_expr};
return IndexMask::from_expr(complement_expr, universe, memory);

View File

@ -112,7 +112,7 @@ bool has_anything_selected(const VArray<bool> &varray, IndexRange range_to_check
* Find curves that have any point selected (a selection factor greater than zero),
* or curves that have their own selection factor greater than zero.
*/
IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
IndexMask retrieve_selected_curves(const Curves &curves_id, IndexMaskMemory &memory);
/**
* Find points that are selected (a selection factor greater than zero),

View File

@ -97,7 +97,7 @@ struct CombOperationExecutor {
CurvesGeometry *curves_orig_ = nullptr;
VArray<float> point_factors_;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
float2 brush_pos_prev_re_;
@ -135,7 +135,7 @@ struct CombOperationExecutor {
point_factors_ = curves_orig_->attributes().lookup_or_default<float>(
".selection", ATTR_DOMAIN_POINT, 1.0f);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_orig_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_orig_, selected_curve_memory_);
brush_pos_prev_re_ = self_->brush_pos_last_re_;
brush_pos_re_ = stroke_extension.mouse_position;

View File

@ -71,7 +71,7 @@ struct DeleteOperationExecutor {
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
const CurvesSculpt *curves_sculpt_ = nullptr;
@ -95,8 +95,7 @@ struct DeleteOperationExecutor {
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &curves_id_->geometry.wrap();
selected_curve_indices_.clear();
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);

View File

@ -507,7 +507,7 @@ struct DensitySubtractOperationExecutor {
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
Object *surface_ob_orig_ = nullptr;
@ -572,7 +572,7 @@ struct DensitySubtractOperationExecutor {
minimum_distance_ = brush_->curves_sculpt_settings->minimum_distance;
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(

View File

@ -245,7 +245,7 @@ struct CurvesEffectOperationExecutor {
CurvesGeometry *curves_ = nullptr;
VArray<float> curve_selection_factors_;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
const Brush *brush_ = nullptr;
@ -286,7 +286,7 @@ struct CurvesEffectOperationExecutor {
curve_selection_factors_ = curves_->attributes().lookup_or_default(
".selection", ATTR_DOMAIN_CURVE, 1.0f);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
const CurvesSculpt &curves_sculpt = *ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint);

View File

@ -68,7 +68,7 @@ struct PinchOperationExecutor {
CurvesGeometry *curves_ = nullptr;
VArray<float> point_factors_;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
CurvesSurfaceTransforms transforms_;
@ -110,7 +110,7 @@ struct PinchOperationExecutor {
point_factors_ = curves_->attributes().lookup_or_default<float>(
".selection", ATTR_DOMAIN_POINT, 1.0f);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
brush_pos_re_ = stroke_extension.mouse_position;
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(

View File

@ -56,7 +56,7 @@ struct PuffOperationExecutor {
CurvesGeometry *curves_ = nullptr;
VArray<float> point_factors_;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
const CurvesSculpt *curves_sculpt_ = nullptr;
@ -107,7 +107,7 @@ struct PuffOperationExecutor {
point_factors_ = curves_->attributes().lookup_or_default<float>(
".selection", ATTR_DOMAIN_POINT, 1.0f);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);

View File

@ -111,7 +111,7 @@ struct SlideOperationExecutor {
BVHTreeFromMesh surface_bvh_eval_;
VArray<float> curve_factors_;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
float2 brush_pos_re_;
@ -159,7 +159,7 @@ struct SlideOperationExecutor {
curve_factors_ = curves_orig_->attributes().lookup_or_default(
".selection", ATTR_DOMAIN_CURVE, 1.0f);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_orig_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_orig_, selected_curve_memory_);
brush_pos_re_ = stroke_extension.mouse_position;

View File

@ -44,7 +44,7 @@ struct SmoothOperationExecutor {
CurvesGeometry *curves_ = nullptr;
VArray<float> point_factors_;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
const CurvesSculpt *curves_sculpt_ = nullptr;
@ -81,7 +81,7 @@ struct SmoothOperationExecutor {
point_factors_ = curves_->attributes().lookup_or_default<float>(
".selection", ATTR_DOMAIN_POINT, 1.0f);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(

View File

@ -85,7 +85,7 @@ struct SnakeHookOperatorExecutor {
CurvesGeometry *curves_ = nullptr;
VArray<float> curve_factors_;
Vector<int64_t> selected_curve_indices_;
IndexMaskMemory selected_curve_memory_;
IndexMask curve_selection_;
CurvesSurfaceTransforms transforms_;
@ -126,7 +126,7 @@ struct SnakeHookOperatorExecutor {
curve_factors_ = curves_->attributes().lookup_or_default(
".selection", ATTR_DOMAIN_CURVE, 1.0f);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_indices_);
curve_selection_ = curves::retrieve_selected_curves(*curves_id_, selected_curve_memory_);
brush_pos_prev_re_ = self.last_mouse_position_re_;
brush_pos_re_ = stroke_extension.mouse_position;

View File

@ -403,9 +403,9 @@ IndexMask GeometryDataSource::apply_selection_filter(IndexMaskMemory &memory) co
const Curves &curves_id = *component.get_for_read();
switch (domain_) {
case ATTR_DOMAIN_POINT:
return curves::retrieve_selected_points(curves_id, indices);
return curves::retrieve_selected_points(curves_id, memory);
case ATTR_DOMAIN_CURVE:
return curves::retrieve_selected_curves(curves_id, indices);
return curves::retrieve_selected_curves(curves_id, memory);
default:
BLI_assert_unreachable();
}

View File

@ -304,6 +304,7 @@ static IndexMask apply_row_filter(const SpreadsheetRowFilter &row_filter,
prev_mask,
memory);
}
return prev_mask;
}
static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)