diff --git a/include/geode/basic/cached_value.hpp b/include/geode/basic/cached_value.hpp index f49dde319..1eb574d40 100644 --- a/include/geode/basic/cached_value.hpp +++ b/include/geode/basic/cached_value.hpp @@ -23,10 +23,13 @@ #pragma once +#include #include #include +#include + #include namespace geode @@ -39,14 +42,44 @@ namespace geode using CachedFunction = typename std::add_pointer< ReturnType( Args... ) >::type; + CachedValue() = default; + CachedValue( const CachedValue& other ) + { + value_ = other.value_; + computed_ = other.computed_.load(); + } + CachedValue( CachedValue&& other ) noexcept + { + value_ = std::move( other.value_ ); + computed_ = other.computed_.load(); + } + + CachedValue& operator=( const CachedValue& other ) + { + value_ = other.value_; + computed_ = other.computed_.load(); + return *this; + } + + CachedValue& operator=( CachedValue&& other ) noexcept + { + value_ = std::move( other.value_ ); + computed_ = other.computed_.load(); + return *this; + } + template < typename... Args > const ReturnType& operator()( CachedFunction< Args... > computer, Args&&... args ) const { if( !computed_ ) { - value_ = computer( std::forward< Args >( args )... ); - computed_ = true; + absl::MutexLock lock{ &mutex_ }; + if( !computed_ ) + { + value_ = computer( std::forward< Args >( args )... ); + computed_ = true; + } } return value_; } @@ -83,7 +116,9 @@ namespace geode archive.ext( *this, Growable< Archive, CachedValue >{ { []( Archive& a, CachedValue& value ) { - a.value1b( value.computed_ ); + bool computed; + a.value1b( computed ); + value.computed_ = computed; a( value.value_ ); }, []( Archive& /*a*/, CachedValue& /*value*/ ) { @@ -92,7 +127,8 @@ namespace geode } private: - mutable bool computed_{ false }; + mutable std::atomic< bool > computed_{ false }; mutable ReturnType value_; + mutable absl::Mutex mutex_; }; } // namespace geode \ No newline at end of file diff --git a/include/geode/mesh/helpers/detail/split_along_solid_facets.hpp b/include/geode/mesh/helpers/detail/split_along_solid_facets.hpp index e86a0e09c..348d061b7 100644 --- a/include/geode/mesh/helpers/detail/split_along_solid_facets.hpp +++ b/include/geode/mesh/helpers/detail/split_along_solid_facets.hpp @@ -41,6 +41,17 @@ namespace geode { namespace detail { + struct SolidInfo + { + SolidInfo( index_t nb_vertices ) + : polyhedron_vertices( nb_vertices ), + vertices_to_check( nb_vertices, false ) + { + } + absl::FixedArray< PolyhedraAroundVertex > polyhedron_vertices; + std::vector< bool > vertices_to_check; + }; + class opengeode_mesh_api SplitAlongSolidFacets { public: @@ -55,6 +66,13 @@ namespace geode MeshesElementsMapping split_solid_along_facets( absl::Span< const PolyhedronFacet > facets_list ); + SolidInfo remove_adjacencies_along_facets( + absl::Span< const PolyhedronFacet > facets_list ); + + MeshesElementsMapping + duplicate_points_and_process_solid_facets_and_edges( + const SolidInfo& solid_info ); + private: IMPLEMENTATION_MEMBER( impl_ ); }; diff --git a/src/geode/mesh/core/solid_mesh.cpp b/src/geode/mesh/core/solid_mesh.cpp index 392ac6e46..f2bdbb446 100644 --- a/src/geode/mesh/core/solid_mesh.cpp +++ b/src/geode/mesh/core/solid_mesh.cpp @@ -571,13 +571,11 @@ namespace geode void enable_edges( const SolidMesh< dimension >& solid ) const { { - absl::ReaderMutexLock lock{ &mutex_ }; if( are_edges_enabled() ) { return; } } - absl::MutexLock lock{ &mutex_ }; edges_.reset( new SolidEdges< dimension >{ solid } ); } @@ -620,13 +618,11 @@ namespace geode void enable_facets( const SolidMesh< dimension >& solid ) const { { - absl::ReaderMutexLock lock{ &mutex_ }; if( are_facets_enabled() ) { return; } } - absl::MutexLock lock{ &mutex_ }; facets_.reset( new SolidFacets< dimension >{ solid } ); } @@ -677,21 +673,14 @@ namespace geode const std::optional< PolyhedronVertex >& first_polyhedron ) const { + const auto& cached = polyhedra_around_vertex_->value( vertex_id ); + if( cached.computed() + && ( first_polyhedron + && absl::c_contains( cached.value().polyhedra, + first_polyhedron.value() ) ) ) { - absl::ReaderMutexLock lock{ &mutex_ }; - const auto& cached = - polyhedra_around_vertex_->value( vertex_id ); - const auto& polyhedra = cached.value().polyhedra; - if( cached.computed() - && ( first_polyhedron - && absl::c_contains( - polyhedra, first_polyhedron.value() ) ) ) - { - return cached.value(); - } + return cached.value(); } - absl::MutexLock lock{ &mutex_ }; - const auto& cached = polyhedra_around_vertex_->value( vertex_id ); cached( compute_polyhedra_around_vertex, mesh, vertex_id, first_polyhedron ); return cached.value(); @@ -804,7 +793,6 @@ namespace geode mutable std::unique_ptr< SolidEdges< dimension > > edges_; mutable std::unique_ptr< SolidFacets< dimension > > facets_; mutable TextureStorage3D texture_storage_; - mutable absl::Mutex mutex_; }; template < index_t dimension > diff --git a/src/geode/mesh/core/surface_mesh.cpp b/src/geode/mesh/core/surface_mesh.cpp index 551ecca52..0d9fa400b 100644 --- a/src/geode/mesh/core/surface_mesh.cpp +++ b/src/geode/mesh/core/surface_mesh.cpp @@ -348,13 +348,11 @@ namespace geode void enable_edges( const SurfaceMesh< dimension >& surface ) const { { - absl::ReaderMutexLock lock{ &mutex_ }; if( are_edges_enabled() ) { return; } } - absl::MutexLock lock{ &mutex_ }; edges_.reset( new SurfaceEdges< dimension >{ surface } ); } @@ -503,21 +501,14 @@ namespace geode const index_t vertex_id, const std::optional< PolygonVertex >& first_polygon ) const { + const auto& cached = polygons_around_vertex_->value( vertex_id ); + if( cached.computed() + && ( first_polygon + && absl::c_contains( + cached.value().polygons, first_polygon.value() ) ) ) { - absl::ReaderMutexLock lock{ &mutex_ }; - const auto& cached = - polygons_around_vertex_->value( vertex_id ); - const auto& polygons = cached.value().polygons; - if( cached.computed() - && ( first_polygon - && absl::c_contains( - polygons, first_polygon.value() ) ) ) - { - return cached.value(); - } + return cached.value(); } - absl::MutexLock lock{ &mutex_ }; - const auto& cached = polygons_around_vertex_->value( vertex_id ); cached( compute_polygons_around_vertex, mesh, vertex_id, first_polygon ); return cached.value(); @@ -531,7 +522,6 @@ namespace geode polygons_around_vertex_; mutable std::unique_ptr< SurfaceEdges< dimension > > edges_; mutable TextureStorage2D texture_storage_; - mutable absl::Mutex mutex_; }; template < index_t dimension > diff --git a/src/geode/mesh/helpers/detail/split_along_solid_facets.cpp b/src/geode/mesh/helpers/detail/split_along_solid_facets.cpp index 007088892..f263e333e 100644 --- a/src/geode/mesh/helpers/detail/split_along_solid_facets.cpp +++ b/src/geode/mesh/helpers/detail/split_along_solid_facets.cpp @@ -41,50 +41,12 @@ namespace geode { class SplitAlongSolidFacets::Impl { - struct SolidInfo - { - SolidInfo( index_t nb_vertices ) - : polyhedron_vertices( nb_vertices ), - vertices_to_check( nb_vertices, false ) - { - } - absl::FixedArray< PolyhedraAroundVertex > polyhedron_vertices; - std::vector< bool > vertices_to_check; - }; - public: Impl( const SolidMesh3D& mesh, SolidMeshBuilder3D& builder ) : solid_( mesh ), builder_( builder ) { } - MeshesElementsMapping split_solid_along_facets( - absl::Span< const PolyhedronFacet > facets_list ) - { - bool facets_enabled = solid_.are_facets_enabled(); - bool edges_enabled = solid_.are_edges_enabled(); - const auto nb_initial_facets = - facets_enabled ? solid_.facets().nb_facets() : 0; - const auto nb_initial_edges = - edges_enabled ? solid_.edges().nb_edges() : 0; - const auto solid_info = - remove_adjacencies_along_facets( facets_list ); - MeshesElementsMapping mapping; - mapping.vertices = duplicate_points( solid_info ); - if( facets_enabled ) - { - mapping.polygons = process_solid_facets( - nb_initial_facets, mapping.vertices ); - } - if( edges_enabled ) - { - mapping.edges = process_solid_edges( - nb_initial_edges, mapping.vertices ); - } - return mapping; - } - - private: SolidInfo remove_adjacencies_along_facets( absl::Span< const PolyhedronFacet > facets_list ) { @@ -122,6 +84,58 @@ namespace geode return info; } + MeshesElementsMapping + duplicate_points_and_process_solid_facets_and_edges( + const SolidInfo& solid_info ) + { + bool facets_enabled = solid_.are_facets_enabled(); + bool edges_enabled = solid_.are_edges_enabled(); + const auto nb_initial_facets = + facets_enabled ? solid_.facets().nb_facets() : 0; + const auto nb_initial_edges = + edges_enabled ? solid_.edges().nb_edges() : 0; + MeshesElementsMapping mapping; + mapping.vertices = duplicate_points( solid_info ); + if( facets_enabled ) + { + mapping.polygons = process_solid_facets( + nb_initial_facets, mapping.vertices ); + } + if( edges_enabled ) + { + mapping.edges = process_solid_edges( + nb_initial_edges, mapping.vertices ); + } + return mapping; + } + + MeshesElementsMapping split_solid_along_facets( + absl::Span< const PolyhedronFacet > facets_list ) + { + const auto solid_info = + remove_adjacencies_along_facets( facets_list ); + bool facets_enabled = solid_.are_facets_enabled(); + bool edges_enabled = solid_.are_edges_enabled(); + const auto nb_initial_facets = + facets_enabled ? solid_.facets().nb_facets() : 0; + const auto nb_initial_edges = + edges_enabled ? solid_.edges().nb_edges() : 0; + MeshesElementsMapping mapping; + mapping.vertices = duplicate_points( solid_info ); + if( facets_enabled ) + { + mapping.polygons = process_solid_facets( + nb_initial_facets, mapping.vertices ); + } + if( edges_enabled ) + { + mapping.edges = process_solid_edges( + nb_initial_edges, mapping.vertices ); + } + return mapping; + } + + private: ElementsMapping duplicate_points( const SolidInfo& solid_info ) { ElementsMapping vertices_mapping; @@ -316,7 +330,21 @@ namespace geode { } - SplitAlongSolidFacets::~SplitAlongSolidFacets() {} + SplitAlongSolidFacets::~SplitAlongSolidFacets() = default; + + SolidInfo SplitAlongSolidFacets::remove_adjacencies_along_facets( + absl::Span< const PolyhedronFacet > facets_list ) + { + return impl_->remove_adjacencies_along_facets( facets_list ); + } + + MeshesElementsMapping SplitAlongSolidFacets:: + duplicate_points_and_process_solid_facets_and_edges( + const SolidInfo& solid_info ) + { + return impl_->duplicate_points_and_process_solid_facets_and_edges( + solid_info ); + } MeshesElementsMapping SplitAlongSolidFacets::split_solid_along_facets( absl::Span< const PolyhedronFacet > facets_list ) diff --git a/src/geode/model/helpers/detail/split_along_block_mesh_borders.cpp b/src/geode/model/helpers/detail/split_along_block_mesh_borders.cpp index d08ed5aa0..a474b5597 100644 --- a/src/geode/model/helpers/detail/split_along_block_mesh_borders.cpp +++ b/src/geode/model/helpers/detail/split_along_block_mesh_borders.cpp @@ -59,41 +59,77 @@ namespace geode CMVmappings split() { - using Task = + using AdjacencyTask = + async::task< std::pair< uuid, SolidInfo > >; + using DuplicateTask = async::task< std::pair< uuid, MeshesElementsMapping > >; - absl::FixedArray< Task > tasks( model_.nb_blocks() ); - index_t count{ 0 }; + absl::FixedArray< AdjacencyTask > adjacency_tasks( + model_.nb_blocks() ); + index_t adjacency_count{ 0 }; for( const auto& block : model_.blocks() ) { - tasks[count++] = async::spawn( [this, &block] { - const auto& mesh = block.mesh(); - auto builder = - builder_.block_mesh_builder( block.id() ); - const auto facets_list = mesh_border_facets( block ); - SplitAlongSolidFacets block_splitter{ mesh, *builder }; - return std::make_pair( - block.id(), block_splitter.split_solid_along_facets( - facets_list ) ); - } ); + adjacency_tasks[adjacency_count++] = + async::spawn( [this, &block] { + const auto& mesh = block.mesh(); + auto builder = + builder_.block_mesh_builder( block.id() ); + const auto facets_list = + mesh_border_facets( block ); + SplitAlongSolidFacets block_splitter{ mesh, + *builder }; + return std::pair{ block.id(), + block_splitter.remove_adjacencies_along_facets( + facets_list ) }; + } ); } CMVmappings mapping; - async::when_all( tasks ) - .then( [this, &mapping]( std::vector< Task > all_task ) { - for( auto& task : all_task ) + async::when_all( adjacency_tasks ) + .then( [this, &mapping]( std::vector< AdjacencyTask > + all_adjacency_tasks ) { + absl::FixedArray< DuplicateTask > duplicate_tasks( + model_.nb_blocks() ); + index_t duplicate_count{ 0 }; + for( auto& task : all_adjacency_tasks ) { const auto result = task.get(); - auto cmv_mapping = update_unique_vertices( - model_.block( result.first ), - result.second.vertices ); - if( !cmv_mapping.empty() ) - { - mapping.insert( mapping.end(), - std::make_move_iterator( - cmv_mapping.begin() ), - std::make_move_iterator( - cmv_mapping.end() ) ); - } + const auto& block = model_.block( result.first ); + const auto solid_info = result.second; + duplicate_tasks[duplicate_count++] = + async::spawn( [this, &block, solid_info] { + const auto& mesh = block.mesh(); + auto builder = builder_.block_mesh_builder( + block.id() ); + const auto facets_list = + mesh_border_facets( block ); + SplitAlongSolidFacets block_splitter{ mesh, + *builder }; + return std::make_pair( block.id(), + block_splitter + .duplicate_points_and_process_solid_facets_and_edges( + solid_info ) ); + } ); } + async::when_all( duplicate_tasks ) + .then( [this, &mapping]( + std::vector< DuplicateTask > + all_duplicate_task ) { + for( auto& task : all_duplicate_task ) + { + const auto result = task.get(); + auto cmv_mapping = update_unique_vertices( + model_.block( result.first ), + result.second.vertices ); + if( !cmv_mapping.empty() ) + { + mapping.insert( mapping.end(), + std::make_move_iterator( + cmv_mapping.begin() ), + std::make_move_iterator( + cmv_mapping.end() ) ); + } + } + } ) + .get(); } ) .get(); return mapping; diff --git a/src/geode/model/helpers/detail/split_along_surface_mesh_borders.cpp b/src/geode/model/helpers/detail/split_along_surface_mesh_borders.cpp index 0bbaa2eac..9577e0af4 100644 --- a/src/geode/model/helpers/detail/split_along_surface_mesh_borders.cpp +++ b/src/geode/model/helpers/detail/split_along_surface_mesh_borders.cpp @@ -24,6 +24,7 @@ #include #include +#include #include @@ -54,7 +55,8 @@ namespace geode using CMVmapping = std::pair< ComponentMeshVertex, ComponentMeshVertex >; using CMVmappings = std::vector< CMVmapping >; - using Task = async::task< CMVmappings >; + using AdjacencyTask = async::task< void >; + using DuplicateTask = async::task< CMVmappings >; using ModelBuilder = typename Model::Builder; static constexpr auto dimension = Model::dim; struct SurfaceInfo @@ -82,27 +84,49 @@ namespace geode CMVmappings split() { - absl::FixedArray< Task > tasks( model_.nb_surfaces() ); - index_t count{ 0 }; + absl::FixedArray< AdjacencyTask > adjacency_tasks( + model_.nb_surfaces() ); + index_t adjacency_count{ 0 }; for( const auto& surface : model_.surfaces() ) { - tasks[count++] = async::spawn( [this, &surface] { - return split_points( surface ); - } ); + adjacency_tasks[adjacency_count++] = + async::spawn( [this, &surface] { + return remove_adjacencies_along_internal_lines( + surface ); + } ); } CMVmappings mapping; - async::when_all( tasks ) - .then( [this, &mapping]( std::vector< Task > all_task ) { - for( auto& task : all_task ) + async::when_all( adjacency_tasks ) + .then( [this, &mapping]() { + absl::FixedArray< DuplicateTask > duplicate_tasks( + model_.nb_surfaces() ); + index_t duplicate_count{ 0 }; + for( const auto& surface : model_.surfaces() ) { - auto cmv_mappings = task.get(); - update_unique_vertices( cmv_mappings ); - mapping.insert( mapping.end(), - std::make_move_iterator( cmv_mappings.begin() ), - std::make_move_iterator( cmv_mappings.end() ) ); + duplicate_tasks[duplicate_count++] = + async::spawn( [this, &surface] { + return duplicate_points( surface ); + } ); } + async::when_all( duplicate_tasks ) + .then( + [this, &mapping]( std::vector< DuplicateTask > + all_duplicate_task ) { + for( auto& task : all_duplicate_task ) + { + auto cmv_mappings = task.get(); + update_unique_vertices( cmv_mappings ); + mapping.insert( mapping.end(), + std::make_move_iterator( + cmv_mappings.begin() ), + std::make_move_iterator( + cmv_mappings.end() ) ); + } + } ) + .get(); } ) .get(); + DEBUG( "end of split" ); return mapping; } @@ -125,13 +149,27 @@ namespace geode } } - CMVmappings split_points( const Surface< dimension >& surface ) + void remove_adjacencies_along_internal_lines( + const Surface< dimension >& surface ) { auto builder = builder_.surface_mesh_builder( surface.id() ); remove_adjacencies_along_internal_lines( surface, *builder ); + } + + CMVmappings duplicate_points( const Surface< dimension >& surface ) + { + auto builder = builder_.surface_mesh_builder( surface.id() ); return duplicate_points( surface, *builder ); } + CMVmappings split_points( const Surface< dimension >& surface ) + { + auto builder = builder_.surface_mesh_builder( surface.id() ); + remove_adjacencies_along_internal_lines( surface, *builder ); + const auto result = duplicate_points( surface, *builder ); + return result; + } + CMVmappings duplicate_points( const Surface< dimension >& surface, SurfaceMeshBuilder< dimension >& builder ) { @@ -288,9 +326,8 @@ namespace geode } template < typename Model > - SplitAlongSurfaceMeshBorders< Model >::~SplitAlongSurfaceMeshBorders() - { - } + SplitAlongSurfaceMeshBorders< Model >::~SplitAlongSurfaceMeshBorders() = + default; template < typename Model > std::vector< std::pair< ComponentMeshVertex, ComponentMeshVertex > >