Performance improvements for zone filler.

This commit is contained in:
Jeff Young 2022-02-15 15:19:39 +00:00
parent 8e26946567
commit d8c4f2cb09
6 changed files with 54 additions and 90 deletions

View File

@ -2204,20 +2204,17 @@ SHAPE_POLY_SET &SHAPE_POLY_SET::operator=( const SHAPE_POLY_SET& aOther )
{
static_cast<SHAPE&>(*this) = aOther;
m_polys = aOther.m_polys;
m_triangulatedPolys.clear();
m_triangulationValid = false;
if( aOther.IsTriangulationUpToDate() )
{
m_triangulatedPolys.clear();
for( unsigned i = 0; i < aOther.TriangulatedPolyCount(); i++ )
{
const TRIANGULATED_POLYGON* poly = aOther.TriangulatedPolygon( i );
m_triangulatedPolys.push_back( std::make_unique<TRIANGULATED_POLYGON>( *poly ) );
}
m_hash = aOther.GetHash();
m_triangulationValid = true;
}
m_hash = aOther.m_hash;
m_triangulationValid = aOther.m_triangulationValid;
return *this;
}

View File

@ -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<ZONE*>& aZones )
{
std::vector<ZONE*> zones = aZones;
if( zones.empty() )
zones = m_zones;
if( zones.empty() )
return;
if( aReporter )
aReporter->Report( _( "Tessellating copper zones..." ) );
std::atomic<size_t> next( 0 );
std::atomic<size_t> count_done( 0 );
std::atomic<size_t> zones_done( 0 );
std::atomic<size_t> threads_done( 0 );
size_t parallelThreadCount = std::max<size_t>( 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 ) );
}
}

View File

@ -308,7 +308,8 @@ public:
*/
void FinalizeBulkRemove( std::vector<BOARD_ITEM*>& aRemovedItems );
void CacheTriangulation( PROGRESS_REPORTER* aReporter = nullptr );
void CacheTriangulation( PROGRESS_REPORTER* aReporter = nullptr,
const std::vector<ZONE*>& aZones = {} );
/**
* Get the first footprint on the board or nullptr.

View File

@ -619,10 +619,23 @@ void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( ZONE* aZone, PCB_LAYER_ID
void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& 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 );

View File

@ -292,9 +292,6 @@ public:
{
const SHAPE_POLY_SET& fill = aParent->GetFilledPolysList( aLayer );
if( !fill.IsTriangulationUpToDate() )
const_cast<SHAPE_POLY_SET&>( fill ).CacheTriangulation();
m_triangulatedPoly = fill;
for( unsigned int ii = 0; ii < m_triangulatedPoly.TriangulatedPolyCount(); ++ii )

View File

@ -79,6 +79,7 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& aZones, bool aCheck, wxWindow* aPare
std::lock_guard<KISPINLOCK> lock( m_board->GetConnectivity()->GetLock() );
std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
std::map<std::pair<ZONE*, PCB_LAYER_ID>, MD5_HASH> oldFillHashes;
std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> islandsList;
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
@ -155,6 +156,7 @@ bool ZONE_FILLER::Fill( std::vector<ZONE*>& 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<ZONE*>& 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<ZONE*>& 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<ZONE*>& 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<ZONE*>& 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<std::future<size_t>> 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() )