Mesh: Use shared cache for shrinkwrap boundary data

This is mainly to make the computation threadsafe, to allow computing
the cache on a const mesh, and also to decrease the cost of copying
meshes. Computing caches on const meshes generally makes it easier
to avoid copying meshes unnecessarily in other ways, which would be
useful for some pending fixes and cleanups to modifier evaluation.
This commit is contained in:
Hans Goudey 2024-03-27 22:09:51 -04:00
parent 278c5c9c7e
commit b35831ad6c
5 changed files with 33 additions and 26 deletions

View File

@ -140,9 +140,6 @@ struct MeshRuntime {
/** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
BVHCache *bvh_cache = nullptr;
/** Cache of non-manifold boundary data for Shrink-wrap Target Project. */
std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_data;
/** Needed in case we need to lazily initialize the mesh. */
CustomData_MeshMasks cd_mask_extra = {};
@ -204,6 +201,9 @@ struct MeshRuntime {
/** Cache of data about vertices not used by faces. See #Mesh::verts_no_face(). */
SharedCache<LooseVertCache> verts_no_face_cache;
/** Cache of non-manifold boundary data for shrinkwrap target Project. */
SharedCache<ShrinkwrapBoundaryData> shrinkwrap_boundary_cache;
/**
* A bit vector the size of the number of vertices, set to true for the center vertices of
* subdivided faces. The values are set by the subdivision surface modifier and used by

View File

@ -62,7 +62,7 @@ struct ShrinkwrapBoundaryData {
namespace blender::bke::shrinkwrap {
void compute_boundary_data(Mesh *mesh);
const ShrinkwrapBoundaryData &boundary_cache_ensure(const Mesh &mesh);
} // namespace blender::bke::shrinkwrap
@ -80,7 +80,7 @@ struct ShrinkwrapTreeData {
blender::Span<blender::float3> vert_normals;
blender::Span<blender::float3> corner_normals;
const bool *sharp_faces;
ShrinkwrapBoundaryData *boundary;
const ShrinkwrapBoundaryData *boundary;
};
/**

View File

@ -1269,12 +1269,14 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
}
}
static void mesh_build_extra_data(Depsgraph *depsgraph, Object *ob, Mesh *mesh_eval)
static void mesh_build_extra_data(const Depsgraph *depsgraph,
const Object *ob,
const Mesh *mesh_eval)
{
uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id);
if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) {
blender::bke::shrinkwrap::compute_boundary_data(mesh_eval);
blender::bke::shrinkwrap::boundary_cache_ensure(*mesh_eval);
}
}

View File

@ -299,9 +299,9 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
mesh->runtime->verts_no_face_cache.tag_dirty();
mesh->runtime->corner_tris_cache.tag_dirty();
mesh->runtime->corner_tri_faces_cache.tag_dirty();
mesh->runtime->shrinkwrap_boundary_cache.tag_dirty();
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
mesh->runtime->shrinkwrap_data.reset();
mesh->flag &= ~ME_NO_OVERLAPPING_TOPOLOGY;
}
@ -331,7 +331,7 @@ void Mesh::tag_edges_split()
}
this->runtime->subsurf_face_dot_tags.clear_and_shrink();
this->runtime->subsurf_optimal_display_edges.clear_and_shrink();
this->runtime->shrinkwrap_data.reset();
this->runtime->shrinkwrap_boundary_cache.tag_dirty();
}
void Mesh::tag_sharpness_changed()
@ -350,6 +350,7 @@ void Mesh::tag_face_winding_changed()
this->runtime->face_normals_cache.tag_dirty();
this->runtime->corner_normals_cache.tag_dirty();
this->runtime->vert_to_corner_map_cache.tag_dirty();
this->runtime->shrinkwrap_boundary_cache.tag_dirty();
}
void Mesh::tag_positions_changed()
@ -357,6 +358,7 @@ void Mesh::tag_positions_changed()
this->runtime->vert_normals_cache.tag_dirty();
this->runtime->face_normals_cache.tag_dirty();
this->runtime->corner_normals_cache.tag_dirty();
this->runtime->shrinkwrap_boundary_cache.tag_dirty();
this->tag_positions_changed_no_normals();
}
@ -365,6 +367,7 @@ void Mesh::tag_positions_changed_no_normals()
free_bvh_cache(*this->runtime);
this->runtime->corner_tris_cache.tag_dirty();
this->runtime->bounds_cache.tag_dirty();
this->runtime->shrinkwrap_boundary_cache.tag_dirty();
}
void Mesh::tag_positions_changed_uniformly()

View File

@ -142,7 +142,7 @@ bool BKE_shrinkwrap_init_tree(
}
if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
data->boundary = mesh->runtime->shrinkwrap_data.get();
data->boundary = &blender::bke::shrinkwrap::boundary_cache_ensure(*mesh);
}
return true;
@ -179,12 +179,12 @@ static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata,
status[index] = (status[index] == 0) ? side : -1;
}
static std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_build_boundary_data(Mesh *mesh)
static ShrinkwrapBoundaryData shrinkwrap_build_boundary_data(const Mesh &mesh)
{
const Span<float3> positions = mesh->vert_positions();
const Span<int2> edges = mesh->edges();
const Span<int> corner_verts = mesh->corner_verts();
const Span<int> corner_edges = mesh->corner_edges();
const Span<float3> positions = mesh.vert_positions();
const Span<int2> edges = mesh.edges();
const Span<int> corner_verts = mesh.corner_verts();
const Span<int> corner_edges = mesh.corner_edges();
/* Count faces per edge (up to 2). */
Array<int8_t> edge_mode(edges.size(), 0);
@ -196,7 +196,7 @@ static std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_build_boundary_data(Me
}
/* Build the boundary edge bitmask. */
BitVector<> edge_is_boundary(mesh->edges_num, false);
BitVector<> edge_is_boundary(mesh.edges_num, false);
int num_boundary_edges = 0;
for (const int64_t i : edges.index_range()) {
@ -212,10 +212,10 @@ static std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_build_boundary_data(Me
}
/* Allocate the data object. */
std::unique_ptr<ShrinkwrapBoundaryData> data = std::make_unique<ShrinkwrapBoundaryData>();
ShrinkwrapBoundaryData data;
/* Build the boundary corner_tris bit-mask. */
const Span<int3> corner_tris = mesh->corner_tris();
const Span<int3> corner_tris = mesh.corner_tris();
BitVector<> tri_has_boundary(corner_tris.size(), false);
@ -232,7 +232,7 @@ static std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_build_boundary_data(Me
}
/* Find boundary vertices and build a mapping table for compact storage of data. */
Array<int> vert_boundary_id(mesh->verts_num, 0);
Array<int> vert_boundary_id(mesh.verts_num, 0);
for (const int64_t i : edges.index_range()) {
if (edge_is_boundary[i]) {
@ -265,7 +265,7 @@ static std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_build_boundary_data(Me
}
/* Finalize average direction and compute normal. */
const Span<float3> vert_normals = mesh->vert_normals();
const Span<float3> vert_normals = mesh.vert_normals();
for (const int64_t i : positions.index_range()) {
int bidx = vert_boundary_id[i];
@ -281,17 +281,19 @@ static std::unique_ptr<ShrinkwrapBoundaryData> shrinkwrap_build_boundary_data(Me
}
}
data->edge_is_boundary = std::move(edge_is_boundary);
data->tri_has_boundary = std::move(tri_has_boundary);
data->vert_boundary_id = std::move(vert_boundary_id);
data->boundary_verts = std::move(boundary_verts);
data.edge_is_boundary = std::move(edge_is_boundary);
data.tri_has_boundary = std::move(tri_has_boundary);
data.vert_boundary_id = std::move(vert_boundary_id);
data.boundary_verts = std::move(boundary_verts);
return data;
}
void compute_boundary_data(Mesh *mesh)
const ShrinkwrapBoundaryData &boundary_cache_ensure(const Mesh &mesh)
{
mesh->runtime->shrinkwrap_data = blender::bke::shrinkwrap::shrinkwrap_build_boundary_data(mesh);
mesh.runtime->shrinkwrap_boundary_cache.ensure(
[&](ShrinkwrapBoundaryData &r_data) { r_data = shrinkwrap_build_boundary_data(mesh); });
return mesh.runtime->shrinkwrap_boundary_cache.data();
}
} // namespace blender::bke::shrinkwrap