From d8c4f2cb09816c1480ce979c612b462091cd5b9e Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 15 Feb 2022 15:19:39 +0000 Subject: [PATCH] Performance improvements for zone filler. --- libs/kimath/src/geometry/shape_poly_set.cpp | 17 ++--- pcbnew/board.cpp | 32 ++++++--- pcbnew/board.h | 3 +- pcbnew/connectivity/connectivity_algo.cpp | 13 ++++ pcbnew/connectivity/connectivity_items.h | 3 - pcbnew/zone_filler.cpp | 76 +++------------------ 6 files changed, 54 insertions(+), 90 deletions(-) diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp index e02675143a..a82ddaee74 100644 --- a/libs/kimath/src/geometry/shape_poly_set.cpp +++ b/libs/kimath/src/geometry/shape_poly_set.cpp @@ -2204,21 +2204,18 @@ SHAPE_POLY_SET &SHAPE_POLY_SET::operator=( const SHAPE_POLY_SET& aOther ) { static_cast(*this) = aOther; m_polys = aOther.m_polys; + m_triangulatedPolys.clear(); - m_triangulationValid = false; - if( aOther.IsTriangulationUpToDate() ) + for( unsigned i = 0; i < aOther.TriangulatedPolyCount(); i++ ) { - for( unsigned i = 0; i < aOther.TriangulatedPolyCount(); i++ ) - { - const TRIANGULATED_POLYGON* poly = aOther.TriangulatedPolygon( i ); - m_triangulatedPolys.push_back( std::make_unique( *poly ) ); - } - - m_hash = aOther.GetHash(); - m_triangulationValid = true; + const TRIANGULATED_POLYGON* poly = aOther.TriangulatedPolygon( i ); + m_triangulatedPolys.push_back( std::make_unique( *poly ) ); } + m_hash = aOther.m_hash; + m_triangulationValid = aOther.m_triangulationValid; + return *this; } diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 7b1b287209..b87fd150d0 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -621,39 +621,51 @@ void BOARD::SetZoneSettings( const ZONE_SETTINGS& aSettings ) } -void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter ) +void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter, const std::vector& aZones ) { + std::vector zones = aZones; + + if( zones.empty() ) + zones = m_zones; + + if( zones.empty() ) + return; + if( aReporter ) aReporter->Report( _( "Tessellating copper zones..." ) ); std::atomic next( 0 ); - std::atomic count_done( 0 ); + std::atomic zones_done( 0 ); + std::atomic threads_done( 0 ); size_t parallelThreadCount = std::max( std::thread::hardware_concurrency(), 2 ); for( size_t ii = 0; ii < parallelThreadCount; ++ii ) { std::thread t = std::thread( - [ this, &count_done, &next ]( ) + [ &zones, &zones_done, &threads_done, &next ]( ) { - for( size_t i = next.fetch_add( 1 ); i < m_zones.size(); i = next.fetch_add( 1 ) ) - m_zones[i]->CacheTriangulation(); + for( size_t i = next.fetch_add( 1 ); i < zones.size(); i = next.fetch_add( 1 ) ) + { + zones[i]->CacheTriangulation(); + zones_done.fetch_add( 1 ); + } - count_done++; + threads_done.fetch_add( 1 ); } ); t.detach(); } // Finalize the triangulation threads - while( count_done < parallelThreadCount ) + while( threads_done < parallelThreadCount ) { - if( aReporter && m_zones.size() ) + if( aReporter ) { - aReporter->SetCurrentProgress( (double) count_done / (double) m_zones.size() ); + aReporter->SetCurrentProgress( (double) zones_done / (double) zones.size() ); aReporter->KeepRefreshing(); } - std::this_thread::sleep_for( std::chrono::milliseconds( 30 ) ); + std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); } } diff --git a/pcbnew/board.h b/pcbnew/board.h index aac11b0d43..92f44aa296 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -308,7 +308,8 @@ public: */ void FinalizeBulkRemove( std::vector& aRemovedItems ); - void CacheTriangulation( PROGRESS_REPORTER* aReporter = nullptr ); + void CacheTriangulation( PROGRESS_REPORTER* aReporter = nullptr, + const std::vector& aZones = {} ); /** * Get the first footprint on the board or nullptr. diff --git a/pcbnew/connectivity/connectivity_algo.cpp b/pcbnew/connectivity/connectivity_algo.cpp index 05005dc2d5..c3dae75dd3 100644 --- a/pcbnew/connectivity/connectivity_algo.cpp +++ b/pcbnew/connectivity/connectivity_algo.cpp @@ -619,10 +619,23 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector& aZones ) { + int delta = 10; // Number of additions between 2 calls to the progress bar + int ii = 0; + for( CN_ZONE_ISOLATED_ISLAND_LIST& z : aZones ) { Remove( z.m_zone ); Add( z.m_zone ); + ii++; + + if( m_progressReporter && ( ii % delta ) == 0 ) + { + m_progressReporter->SetCurrentProgress( (double) ii / (double) aZones.size() ); + m_progressReporter->KeepRefreshing( false ); + } + + if( m_progressReporter && m_progressReporter->IsCancelled() ) + return; } m_connClusters = SearchClusters( CSM_CONNECTIVITY_CHECK ); diff --git a/pcbnew/connectivity/connectivity_items.h b/pcbnew/connectivity/connectivity_items.h index 8403d7a864..d884d49858 100644 --- a/pcbnew/connectivity/connectivity_items.h +++ b/pcbnew/connectivity/connectivity_items.h @@ -292,9 +292,6 @@ public: { const SHAPE_POLY_SET& fill = aParent->GetFilledPolysList( aLayer ); - if( !fill.IsTriangulationUpToDate() ) - const_cast( fill ).CacheTriangulation(); - m_triangulatedPoly = fill; for( unsigned int ii = 0; ii < m_triangulatedPoly.TriangulatedPolyCount(); ++ii ) diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index ff5d1c7ac4..628b211c49 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -78,8 +78,9 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare { std::lock_guard lock( m_board->GetConnectivity()->GetLock() ); - std::vector> toFill; - std::vector islandsList; + std::vector> toFill; + std::map, MD5_HASH> oldFillHashes; + std::vector islandsList; std::shared_ptr connectivity = m_board->GetConnectivity(); @@ -155,6 +156,7 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) { zone->BuildHashValue( layer ); + oldFillHashes[ { zone, layer } ] = zone->GetHashValue( layer ); // Add the zone to the list of zones to test or refill toFill.emplace_back( std::make_pair( zone, layer ) ); @@ -291,6 +293,8 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare break; } + m_board->CacheTriangulation( m_progressReporter, aZones ); + // Now update the connectivity to check for copper islands if( m_progressReporter ) { @@ -387,6 +391,9 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare } } + // Re-cache triangulation after removing islands + m_board->CacheTriangulation( m_progressReporter, aZones ); + if( aCheck ) { bool outOfDate = false; @@ -399,12 +406,9 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) { - MD5_HASH was = zone->GetHashValue( layer ); - zone->CacheTriangulation( layer ); zone->BuildHashValue( layer ); - MD5_HASH is = zone->GetHashValue( layer ); - if( is != was ) + if( oldFillHashes[ { zone, layer } ] != zone->GetHashValue( layer ) ) outOfDate = true; } } @@ -427,66 +431,6 @@ bool ZONE_FILLER::Fill( std::vector& aZones, bool aCheck, wxWindow* aPare } } - if( m_progressReporter ) - { - m_progressReporter->AdvancePhase(); - m_progressReporter->Report( _( "Performing polygon fills..." ) ); - m_progressReporter->SetMaxProgress( islandsList.size() ); - } - - nextItem = 0; - - auto tri_lambda = - [&]( PROGRESS_REPORTER* aReporter ) -> size_t - { - size_t num = 0; - - for( size_t i = nextItem++; i < islandsList.size(); i = nextItem++ ) - { - islandsList[i].m_zone->CacheTriangulation(); - num++; - - if( m_progressReporter ) - { - m_progressReporter->AdvanceProgress(); - - if( m_progressReporter->IsCancelled() ) - break; - } - } - - return num; - }; - - size_t parallelThreadCount = std::min( cores, islandsList.size() ); - std::vector> returns( parallelThreadCount ); - - if( parallelThreadCount <= 1 ) - tri_lambda( m_progressReporter ); - else - { - for( size_t ii = 0; ii < parallelThreadCount; ++ii ) - returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter ); - - for( size_t ii = 0; ii < parallelThreadCount; ++ii ) - { - // Here we balance returns with a 100ms timeout to allow UI updating - std::future_status status; - do - { - if( m_progressReporter ) - { - m_progressReporter->KeepRefreshing(); - - if( m_progressReporter->IsCancelled() ) - break; - } - - status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) ); - } while( status != std::future_status::ready ); - } - } - if( m_progressReporter ) { if( m_progressReporter->IsCancelled() )