diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h index 25387cc2bad..93b65d1561f 100644 --- a/source/blender/blenkernel/BKE_mesh_types.h +++ b/source/blender/blenkernel/BKE_mesh_types.h @@ -13,6 +13,7 @@ # include "MEM_guardedalloc.h" +# include "BLI_array.hh" # include "BLI_bit_vector.hh" # include "BLI_bounds_types.hh" # include "BLI_math_vec_types.hh" @@ -20,6 +21,7 @@ # include "BLI_span.hh" # include "DNA_customdata_types.h" +# include "DNA_meshdata_types.h" struct BVHCache; struct EditMeshData; @@ -78,19 +80,6 @@ struct LooseEdgeCache { int count = -1; }; -/** - * \warning Typical access is done via #Mesh::looptris(). - */ -struct MLoopTri_Store { - /* WARNING! swapping between array (ready-to-be-used data) and array_wip - * (where data is actually computed) - * shall always be protected by same lock as one used for looptris computing. */ - MLoopTri *array = nullptr; - MLoopTri *array_wip = nullptr; - int len = 0; - int len_alloc = 0; -}; - struct MeshRuntime { /* Evaluated mesh for objects which do not have effective modifiers. * This mesh is used as a result of modifier stack evaluation. @@ -120,8 +109,8 @@ struct MeshRuntime { */ void *batch_cache = nullptr; - /** Cache for derived triangulation of the mesh. */ - MLoopTri_Store looptris; + /** Cache for derived triangulation of the mesh, accessed with #Mesh::looptris(). */ + SharedCache> looptris_cache; /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */ BVHCache *bvh_cache = nullptr; diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 23fee166a0b..02d375bd782 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -129,6 +129,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int * Caches will be "un-shared" as necessary later on. */ mesh_dst->runtime->bounds_cache = mesh_src->runtime->bounds_cache; mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache; + mesh_dst->runtime->looptris_cache = mesh_src->runtime->looptris_cache; /* Only do tessface if we have no polys. */ const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0)); diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc index d62e4442d2a..51c98f6aa6b 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.cc +++ b/source/blender/blenkernel/intern/mesh_runtime.cc @@ -105,23 +105,14 @@ MeshRuntime::~MeshRuntime() BKE_shrinkwrap_boundary_data_free(this->shrinkwrap_data); } MEM_SAFE_FREE(this->subsurf_face_dot_tags); - MEM_SAFE_FREE(this->looptris.array); } } // namespace blender::bke -blender::Span Mesh::looptris() const -{ - const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(this); - const int num_looptris = BKE_mesh_runtime_looptri_len(this); - return {looptris, num_looptris}; -} - const blender::bke::LooseEdgeCache &Mesh::loose_edges() const { using namespace blender::bke; this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) { - SCOPED_TIMER("loose_edges"); blender::BitVector<> &loose_edges = r_data.is_loose_bits; loose_edges.resize(0); loose_edges.resize(this->totedge, true); @@ -149,97 +140,42 @@ void Mesh::loose_edges_tag_none() const }); } -/** - * Ensure the array is large enough - * - * \note This function must always be thread-protected by caller. - * It should only be used by internal code. - */ -static void mesh_ensure_looptri_data(Mesh *mesh) +blender::Span Mesh::looptris() const { - /* This is a ported copy of `DM_ensure_looptri_data(dm)`. */ - const uint totpoly = mesh->totpoly; - const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop); + this->runtime->looptris_cache.ensure([&](blender::Array &r_data) { + const Span verts = this->verts(); + const Span polys = this->polys(); + const Span loops = this->loops(); - BLI_assert(mesh->runtime->looptris.array_wip == nullptr); + r_data.reinitialize(poly_to_tri_count(polys.size(), loops.size())); - SWAP(MLoopTri *, mesh->runtime->looptris.array, mesh->runtime->looptris.array_wip); - - if ((looptris_len > mesh->runtime->looptris.len_alloc) || - (looptris_len < mesh->runtime->looptris.len_alloc * 2) || (totpoly == 0)) { - MEM_SAFE_FREE(mesh->runtime->looptris.array_wip); - mesh->runtime->looptris.len_alloc = 0; - mesh->runtime->looptris.len = 0; - } - - if (totpoly) { - if (mesh->runtime->looptris.array_wip == nullptr) { - mesh->runtime->looptris.array_wip = static_cast( - MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime->looptris.array_wip), __func__)); - mesh->runtime->looptris.len_alloc = looptris_len; + if (BKE_mesh_poly_normals_are_dirty(this)) { + BKE_mesh_recalc_looptri( + loops.data(), polys.data(), verts.data(), loops.size(), polys.size(), r_data.data()); } + else { + BKE_mesh_recalc_looptri_with_normals(loops.data(), + polys.data(), + verts.data(), + loops.size(), + polys.size(), + r_data.data(), + BKE_mesh_poly_normals_ensure(this)); + } + }); - mesh->runtime->looptris.len = looptris_len; - } -} - -static void recalc_loopris(Mesh *mesh) -{ - mesh_ensure_looptri_data(mesh); - BLI_assert(mesh->totpoly == 0 || mesh->runtime->looptris.array_wip != nullptr); - const Span verts = mesh->verts(); - const Span polys = mesh->polys(); - const Span loops = mesh->loops(); - - if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - BKE_mesh_recalc_looptri_with_normals(loops.data(), - polys.data(), - verts.data(), - mesh->totloop, - mesh->totpoly, - mesh->runtime->looptris.array_wip, - BKE_mesh_poly_normals_ensure(mesh)); - } - else { - BKE_mesh_recalc_looptri(loops.data(), - polys.data(), - verts.data(), - mesh->totloop, - mesh->totpoly, - mesh->runtime->looptris.array_wip); - } - - BLI_assert(mesh->runtime->looptris.array == nullptr); - atomic_cas_ptr((void **)&mesh->runtime->looptris.array, - mesh->runtime->looptris.array, - mesh->runtime->looptris.array_wip); - mesh->runtime->looptris.array_wip = nullptr; + return this->runtime->looptris_cache.data(); } int BKE_mesh_runtime_looptri_len(const Mesh *mesh) { - /* This is a ported copy of `dm_getNumLoopTri(dm)`. */ - const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop); - BLI_assert(ELEM(mesh->runtime->looptris.len, 0, looptri_len)); - return looptri_len; + /* Allow returning the size without calculating the cache. */ + return poly_to_tri_count(mesh->totpoly, mesh->totloop); } const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh) { - std::lock_guard lock{mesh->runtime->eval_mutex}; - - MLoopTri *looptri = mesh->runtime->looptris.array; - - if (looptri != nullptr) { - BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime->looptris.len); - } - else { - /* Must isolate multithreaded tasks while holding a mutex lock. */ - blender::threading::isolate_task([&]() { recalc_loopris(const_cast(mesh)); }); - looptri = mesh->runtime->looptris.array; - } - - return looptri; + return mesh->looptris().data(); } void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri, @@ -288,18 +224,18 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) free_subdiv_ccg(*mesh->runtime); mesh->runtime->bounds_cache.tag_dirty(); mesh->runtime->loose_edges_cache.tag_dirty(); + mesh->runtime->looptris_cache.tag_dirty(); if (mesh->runtime->shrinkwrap_data) { BKE_shrinkwrap_boundary_data_free(mesh->runtime->shrinkwrap_data); } MEM_SAFE_FREE(mesh->runtime->subsurf_face_dot_tags); - MEM_SAFE_FREE(mesh->runtime->looptris.array); } void BKE_mesh_tag_coords_changed(Mesh *mesh) { BKE_mesh_normals_tag_dirty(mesh); free_bvh_cache(*mesh->runtime); - MEM_SAFE_FREE(mesh->runtime->looptris.array); + mesh->runtime->looptris_cache.tag_dirty(); mesh->runtime->bounds_cache.tag_dirty(); }