From a3bfd6e20d26f712dc0a21dbec35e5671aeeeb9c Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 3 Jul 2023 18:47:03 -0400 Subject: [PATCH] Cleanup: Extract utility for counting indices This utility counts the number of occurrences of each index in an array. This is used for building mesh topology maps offsets, or for counting the number of connected elements. Some users are geometry nodes, the subdivision draw cache, and mesh to curve conversion. See #109628 --- .../blender/blenkernel/intern/mesh_mapping.cc | 5 +-- source/blender/blenlib/BLI_array_utils.hh | 10 +++++ source/blender/blenlib/intern/array_utils.cc | 9 ++++ .../blender/blenlib/intern/offset_indices.cc | 5 +-- .../intern/draw_cache_impl_subdivision.cc | 19 +++----- source/blender/editors/sculpt_paint/sculpt.cc | 17 ++----- .../geometry/intern/mesh_to_curve_convert.cc | 5 +-- source/blender/modifiers/intern/MOD_skin.cc | 6 +-- .../node_geo_input_mesh_edge_neighbors.cc | 13 ++---- .../node_geo_input_mesh_face_neighbors.cc | 7 +-- .../node_geo_input_mesh_vertex_neighbors.cc | 44 ++++++------------- .../node_geo_mesh_topology_corners_of_edge.cc | 7 +-- ...ode_geo_mesh_topology_corners_of_vertex.cc | 7 +-- .../node_geo_mesh_topology_edges_of_vertex.cc | 8 +--- 14 files changed, 60 insertions(+), 102 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc index b74687dbf6a..60f603ea93a 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.cc +++ b/source/blender/blenkernel/intern/mesh_mapping.cc @@ -301,10 +301,7 @@ namespace blender::bke::mesh { static Array create_reverse_offsets(const Span indices, const int items_num) { Array offsets(items_num + 1, 0); - for (const int i : indices) { - offsets[i]++; - } - offset_indices::accumulate_counts_to_offsets(offsets); + offset_indices::build_reverse_offsets(indices, offsets); return offsets; } diff --git a/source/blender/blenlib/BLI_array_utils.hh b/source/blender/blenlib/BLI_array_utils.hh index 072d0cedb99..68c6a0a9382 100644 --- a/source/blender/blenlib/BLI_array_utils.hh +++ b/source/blender/blenlib/BLI_array_utils.hh @@ -145,6 +145,16 @@ inline void gather(const VArray &src, }); } +/** + * Count the number of occurences of each index. + * \param indices: The indices to count. + * \param counts: The number of occurrences of each index. Typically initialized to zero. + * Must be large enough to contain the maximum index. + * + * \note The memory referenced by the two spans must not overlap. + */ +void count_indices(Span indices, MutableSpan counts); + void invert_booleans(MutableSpan span); enum class BooleanMix { diff --git a/source/blender/blenlib/intern/array_utils.cc b/source/blender/blenlib/intern/array_utils.cc index 912443383e0..8bf98fb070a 100644 --- a/source/blender/blenlib/intern/array_utils.cc +++ b/source/blender/blenlib/intern/array_utils.cc @@ -4,6 +4,8 @@ #include "BLI_array_utils.hh" +#include "atomic_ops.h" + namespace blender::array_utils { void copy(const GVArray &src, GMutableSpan dst, const int64_t grain_size) @@ -45,6 +47,13 @@ void gather(const GSpan src, const IndexMask &indices, GMutableSpan dst, const i gather(GVArray::ForSpan(src), indices, dst, grain_size); } +void count_indices(const Span indices, MutableSpan counts) +{ + for (const int i : indices) { + counts[i]++; + } +} + void invert_booleans(MutableSpan span) { threading::parallel_for(span.index_range(), 4096, [&](IndexRange range) { diff --git a/source/blender/blenlib/intern/offset_indices.cc b/source/blender/blenlib/intern/offset_indices.cc index 5a7d4ae3476..546281f455e 100644 --- a/source/blender/blenlib/intern/offset_indices.cc +++ b/source/blender/blenlib/intern/offset_indices.cc @@ -2,6 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_offset_indices.hh" #include "BLI_task.hh" @@ -63,9 +64,7 @@ void build_reverse_map(OffsetIndices offsets, MutableSpan r_map) void build_reverse_offsets(const Span indices, MutableSpan offsets) { BLI_assert(std::all_of(offsets.begin(), offsets.end(), [](int value) { return value == 0; })); - for (const int i : indices) { - offsets[i]++; - } + array_utils::count_indices(indices, offsets); offset_indices::accumulate_counts_to_offsets(offsets); } diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index fc2363324b1..cf774367791 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -1133,20 +1133,13 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache) cache->subdiv_vertex_face_adjacency_offsets = gpu_vertbuf_create_from_format( get_origindex_format(), cache->num_subdiv_verts + 1); - int *vertex_offsets = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency_offsets); - memset(vertex_offsets, 0, sizeof(int) * cache->num_subdiv_verts + 1); + blender::MutableSpan vertex_offsets( + static_cast(GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency_offsets)), + cache->num_subdiv_verts + 1); + vertex_offsets.fill(0); - for (int i = 0; i < cache->num_subdiv_loops; i++) { - vertex_offsets[cache->subdiv_loop_subdiv_vert_index[i]]++; - } - - int ofs = vertex_offsets[0]; - vertex_offsets[0] = 0; - for (uint i = 1; i < cache->num_subdiv_verts + 1; i++) { - int tmp = vertex_offsets[i]; - vertex_offsets[i] = ofs; - ofs += tmp; - } + blender::offset_indices::build_reverse_offsets( + {cache->subdiv_loop_subdiv_vert_index, cache->num_subdiv_loops}, vertex_offsets); cache->subdiv_vertex_face_adjacency = gpu_vertbuf_create_from_format(get_origindex_format(), cache->num_subdiv_loops); diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index 75efbb79772..1bf4a91e436 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -13,6 +13,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.hh" #include "BLI_blenlib.h" #include "BLI_dial_2d.h" #include "BLI_ghash.h" @@ -6158,20 +6159,12 @@ void SCULPT_boundary_info_ensure(Object *object) } Mesh *base_mesh = BKE_mesh_from_object(object); - const blender::Span edges = base_mesh->edges(); - const OffsetIndices polys = base_mesh->polys(); - const Span corner_edges = base_mesh->corner_edges(); ss->vertex_info.boundary = BLI_BITMAP_NEW(base_mesh->totvert, "Boundary info"); - int *adjacent_faces_edge_count = static_cast( - MEM_calloc_arrayN(base_mesh->totedge, sizeof(int), "Adjacent face edge count")); - - for (const int i : polys.index_range()) { - for (const int edge : corner_edges.slice(polys[i])) { - adjacent_faces_edge_count[edge]++; - } - } + Array adjacent_faces_edge_count(base_mesh->totedge, 0); + array_utils::count_indices(base_mesh->corner_edges(), adjacent_faces_edge_count); + const blender::Span edges = base_mesh->edges(); for (const int e : edges.index_range()) { if (adjacent_faces_edge_count[e] < 2) { const int2 &edge = edges[e]; @@ -6179,8 +6172,6 @@ void SCULPT_boundary_info_ensure(Object *object) BLI_BITMAP_SET(ss->vertex_info.boundary, edge[1], true); } } - - MEM_freeN(adjacent_faces_edge_count); } void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist) diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 1b508a14645..a7fd29a6eb7 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -115,10 +115,7 @@ BLI_NOINLINE static CurveFromEdgesOutput edges_to_curve_point_indices(const int { /* Compute the number of edges connecting to each vertex. */ Array neighbor_offsets_data(verts_num + 1, 0); - for (const int vert : edges.cast()) { - neighbor_offsets_data[vert]++; - } - offset_indices::accumulate_counts_to_offsets(neighbor_offsets_data); + offset_indices::build_reverse_offsets(edges.cast(), neighbor_offsets_data); const OffsetIndices neighbor_offsets(neighbor_offsets_data); /* Use as an index into the "neighbor group" for each vertex. */ diff --git a/source/blender/modifiers/intern/MOD_skin.cc b/source/blender/modifiers/intern/MOD_skin.cc index caec2f193ea..ca1fad51dad 100644 --- a/source/blender/modifiers/intern/MOD_skin.cc +++ b/source/blender/modifiers/intern/MOD_skin.cc @@ -42,6 +42,7 @@ #include "BLI_utildefines.h" +#include "BLI_array_utils.hh" #include "BLI_bitmap.h" #include "BLI_heap_simple.h" #include "BLI_math.h" @@ -911,10 +912,7 @@ static Mesh *subdivide_base(const Mesh *orig) /* Get degree of all vertices */ blender::Array degree(orig_vert_num, 0); - for (i = 0; i < orig_edge_num; i++) { - degree[orig_edges[i][0]]++; - degree[orig_edges[i][1]]++; - } + blender::array_utils::count_indices(orig_edges.cast(), degree); /* Per edge, store how many subdivisions are needed */ blender::Array edge_subd(orig_edge_num, 0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc index deac45754c1..2cb38b266f1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc @@ -2,8 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" +#include "BLI_array_utils.hh" #include "BKE_mesh.hh" @@ -30,14 +29,10 @@ class EdgeNeighborCountFieldInput final : public bke::MeshFieldInput { const eAttrDomain domain, const IndexMask & /*mask*/) const final { - const Span corner_edges = mesh.corner_edges(); - Array face_count(mesh.totedge, 0); - for (const int edge : corner_edges) { - face_count[edge]++; - } - + Array counts(mesh.totedge, 0); + array_utils::count_indices(mesh.corner_edges(), counts); return mesh.attributes().adapt_domain( - VArray::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain); + VArray::ForContainer(std::move(counts)), ATTR_DOMAIN_EDGE, domain); } uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc index a8a707c8739..93e9efb3501 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc @@ -2,8 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" +#include "BLI_array_utils.hh" #include "BKE_mesh.hh" @@ -27,9 +26,7 @@ static VArray construct_neighbor_count_varray(const Mesh &mesh, const eAttr const Span corner_edges = mesh.corner_edges(); Array edge_count(mesh.totedge, 0); - for (const int edge : corner_edges) { - edge_count[edge]++; - } + array_utils::count_indices(corner_edges, edge_count); Array poly_count(polys.size(), 0); for (const int poly_index : polys.index_range()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc index 5fad8cd6dcd..24ebaaecc22 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc @@ -2,8 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" +#include "BLI_array_utils.hh" #include "BKE_mesh.hh" @@ -23,20 +22,6 @@ static void node_declare(NodeDeclarationBuilder &b) .description("Number of faces that contain the vertex"); } -static VArray construct_vertex_count_gvarray(const Mesh &mesh, const eAttrDomain domain) -{ - const Span edges = mesh.edges(); - if (domain == ATTR_DOMAIN_POINT) { - Array counts(mesh.totvert, 0); - for (const int i : edges.index_range()) { - counts[edges[i][0]]++; - counts[edges[i][1]]++; - } - return VArray::ForContainer(std::move(counts)); - } - return {}; -} - class VertexCountFieldInput final : public bke::MeshFieldInput { public: VertexCountFieldInput() : bke::MeshFieldInput(CPPType::get(), "Vertex Count Field") @@ -48,7 +33,12 @@ class VertexCountFieldInput final : public bke::MeshFieldInput { const eAttrDomain domain, const IndexMask & /*mask*/) const final { - return construct_vertex_count_gvarray(mesh, domain); + if (domain != ATTR_DOMAIN_POINT) { + return {}; + } + Array counts(mesh.totvert, 0); + array_utils::count_indices(mesh.edges().cast(), counts); + return VArray::ForContainer(std::move(counts)); } uint64_t hash() const override @@ -68,19 +58,6 @@ class VertexCountFieldInput final : public bke::MeshFieldInput { } }; -static VArray construct_face_count_gvarray(const Mesh &mesh, const eAttrDomain domain) -{ - const Span corner_verts = mesh.corner_verts(); - if (domain == ATTR_DOMAIN_POINT) { - Array vertices(mesh.totvert, 0); - for (const int vert : corner_verts) { - vertices[vert]++; - } - return VArray::ForContainer(std::move(vertices)); - } - return {}; -} - class VertexFaceCountFieldInput final : public bke::MeshFieldInput { public: VertexFaceCountFieldInput() : bke::MeshFieldInput(CPPType::get(), "Vertex Face Count Field") @@ -92,7 +69,12 @@ class VertexFaceCountFieldInput final : public bke::MeshFieldInput { const eAttrDomain domain, const IndexMask & /*mask*/) const final { - return construct_face_count_gvarray(mesh, domain); + if (domain != ATTR_DOMAIN_POINT) { + return {}; + } + Array counts(mesh.totvert, 0); + array_utils::count_indices(mesh.corner_verts(), counts); + return VArray::ForContainer(std::move(counts)); } uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_edge.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_edge.cc index 4e1ee9359cf..046a72dfa89 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_edge.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_edge.cc @@ -5,7 +5,7 @@ #include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" -#include "BLI_task.hh" +#include "BLI_array_utils.hh" #include "node_geometry_util.hh" @@ -151,11 +151,8 @@ class CornersOfEdgeCountInput final : public bke::MeshFieldInput { if (domain != ATTR_DOMAIN_EDGE) { return {}; } - const Span corner_edges = mesh.corner_edges(); Array counts(mesh.totedge, 0); - for (const int i : corner_edges.index_range()) { - counts[corner_edges[i]]++; - } + array_utils::count_indices(mesh.corner_edges(), counts); return VArray::ForContainer(std::move(counts)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc index 63c83ecbbd1..a19365748b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc @@ -5,7 +5,7 @@ #include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" -#include "BLI_task.hh" +#include "BLI_array_utils.hh" #include "node_geometry_util.hh" @@ -158,11 +158,8 @@ class CornersOfVertCountInput final : public bke::MeshFieldInput { if (domain != ATTR_DOMAIN_POINT) { return {}; } - const Span corner_verts = mesh.corner_verts(); Array counts(mesh.totvert, 0); - for (const int i : corner_verts.index_range()) { - counts[corner_verts[i]]++; - } + array_utils::count_indices(mesh.corner_verts(), counts); return VArray::ForContainer(std::move(counts)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc index bbd4ea3c1e2..d892b5efd23 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc @@ -5,7 +5,7 @@ #include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" -#include "BLI_task.hh" +#include "BLI_array_utils.hh" #include "node_geometry_util.hh" @@ -160,12 +160,8 @@ class EdgesOfVertCountInput final : public bke::MeshFieldInput { if (domain != ATTR_DOMAIN_POINT) { return {}; } - const Span edges = mesh.edges(); Array counts(mesh.totvert, 0); - for (const int i : edges.index_range()) { - counts[edges[i][0]]++; - counts[edges[i][1]]++; - } + array_utils::count_indices(mesh.edges().cast(), counts); return VArray::ForContainer(std::move(counts)); }