More DRC performance work.

Push DRC zone RTrees into BOARD so that they can also be used by
insideArea.

All these caches are a bit of an encapsulation leak, but they make a
significant impact on performance.

Fixes https://gitlab.com/kicad/code/kicad/issues/7720
This commit is contained in:
Jeff Young 2021-02-27 00:18:04 +00:00
parent d8089ed54a
commit 4ede4e061e
6 changed files with 62 additions and 48 deletions

View File

@ -35,6 +35,7 @@
#include <pcb_plot_params.h>
#include <title_block.h>
#include <tools/pcb_selection.h>
#include <drc/drc_rtree.h>
class BOARD_COMMIT;
class PCB_BASE_FRAME;
@ -272,6 +273,7 @@ public:
m_timeStamp++;
m_InsideAreaCache.clear();
m_InsideCourtyardCache.clear();
m_CopperZoneRTrees.clear();
}
int GetTimeStamp() { return m_timeStamp; }
@ -1138,8 +1140,11 @@ public:
GroupLegalOpsField GroupLegalOps( const PCB_SELECTION& selection ) const;
public:
// While this is a significant encapsulation leak, it's also a significant performance win.
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, bool> m_InsideCourtyardCache;
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, bool> m_InsideAreaCache;
// ------------ Run-time caches -------------
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, bool > m_InsideCourtyardCache;
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, bool > m_InsideAreaCache;
std::map< ZONE*, std::unique_ptr<DRC_RTREE> > m_CopperZoneRTrees;
};
#endif // CLASS_BOARD_H_

View File

@ -659,7 +659,7 @@ void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aT
if( m_progressReporter )
{
int phases = 0;
int phases = 1;
for( DRC_TEST_PROVIDER* provider : m_testProviders )
{
@ -680,10 +680,20 @@ void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aT
m_board->IncrementTimeStamp(); // Invalidate all caches
if( !ReportPhase( _( "Tessellating copper zones..." ) ) )
return;
// Number of zones between progress bar updates
int delta = 5;
std::vector<ZONE*> copperZones;
for( ZONE* zone : m_board->Zones() )
{
zone->CacheBoundingBox();
zone->CacheTriangulation();
if( !zone->GetIsRuleArea() )
copperZones.push_back( zone );
}
for( FOOTPRINT* footprint : m_board->Footprints() )
@ -692,11 +702,35 @@ void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aT
{
zone->CacheBoundingBox();
zone->CacheTriangulation();
if( !zone->GetIsRuleArea() )
copperZones.push_back( zone );
}
footprint->BuildPolyCourtyards();
}
int zoneCount = copperZones.size();
for( int ii = 0; ii < zoneCount; ++ii )
{
ZONE* zone = copperZones[ ii ];
if( ( ii % delta ) == 0 || ii == zoneCount - 1 )
{
if( !ReportProgress( (double) ii / (double) zoneCount ) )
return;
}
m_board->m_CopperZoneRTrees[ zone ] = std::make_unique<DRC_RTREE>();
for( int layer : zone->GetLayerSet().Seq() )
{
if( IsCopperLayer( layer ) )
m_board->m_CopperZoneRTrees[ zone ]->Insert( zone, layer );
}
}
for( DRC_TEST_PROVIDER* provider : m_testProviders )
{
if( !provider->IsEnabled() )

View File

@ -279,8 +279,11 @@ public:
if( collision )
{
*aActual = std::max( 0, actual );
*aPos = pos;
if( aActual )
*aActual = std::max( 0, actual );
if( aPos )
*aPos = pos;
return true;
}

View File

@ -31,7 +31,6 @@
#include <geometry/shape_poly_set.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_null.h>
#include <drc/drc_rtree.h>
#include <drc/drc_item.h>
@ -92,12 +91,10 @@ private:
void testItemAgainstZones( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer );
private:
DRC_RTREE m_copperTree;
int m_drcEpsilon;
std::vector<ZONE*> m_zones;
std::map<ZONE*, std::unique_ptr<DRC_RTREE>> m_zoneTrees;
DRC_RTREE m_copperTree;
int m_drcEpsilon;
std::vector<ZONE*> m_zones;
};
@ -187,29 +184,6 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run()
forEachGeometryItem( itemTypes, LSET::AllCuMask(), countItems );
forEachGeometryItem( itemTypes, LSET::AllCuMask(), addToCopperTree );
if( !reportPhase( _( "Tessellating copper zones..." ) ) )
return false;
delta = 5;
ii = 0;
m_zoneTrees.clear();
for( ZONE* zone : m_zones )
{
if( !reportProgress( ii++, m_zones.size(), delta ) )
break;
zone->CacheBoundingBox();
m_zoneTrees[ zone ] = std::make_unique<DRC_RTREE>();
for( int layer : zone->GetLayerSet().Seq() )
{
if( IsCopperLayer( layer ) )
m_zoneTrees[ zone ]->Insert( zone, layer );
}
}
reportAux( "Testing %d copper items and %d zones...", count, m_zones.size() );
if( !reportPhase( _( "Checking track & via clearances..." ) ) )
@ -378,10 +352,9 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
if( clearance < 0 )
continue;
int actual;
VECTOR2I pos;
DRC_RTREE* zoneTree = m_zoneTrees[ zone ].get();
int actual;
VECTOR2I pos;
DRC_RTREE* zoneTree = m_board->m_CopperZoneRTrees[ zone ].get();
EDA_RECT itemBBox = aItem->GetBoundingBox();
std::shared_ptr<SHAPE> itemShape = aItem->GetEffectiveShape( aLayer );
@ -430,7 +403,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
{
// This is the number of tests between 2 calls to the progress bar
const int delta = 25;
const int delta = 100;
int ii = 0;
reportAux( "Testing %d tracks & vias...", m_board->Tracks().size() );
@ -880,7 +853,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
int DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetNumPhases() const
{
return 5;
return 4;
}

View File

@ -83,7 +83,7 @@ private:
bool DRC_TEST_PROVIDER_SILK_CLEARANCE::Run()
{
// This is the number of tests between 2 calls to the progress bar
const int delta = 1000;
const int delta = 2000;
m_board = m_drcEngine->GetBoard();

View File

@ -347,16 +347,15 @@ static void insideArea( LIBEVAL::CONTEXT* aCtx, void* self )
if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
{
ZONE* testZone = static_cast<ZONE*>( item );
ZONE* itemZone = static_cast<ZONE*>( item );
DRC_RTREE* itemRTree = board->m_CopperZoneRTrees[ itemZone ].get();
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
{
if( testZone->IsOnLayer( layer ) )
if( itemRTree->QueryColliding( zone->GetCachedBoundingBox(), &zoneOutline,
layer, 0, nullptr, nullptr ) )
{
const SHAPE_POLY_SET& fill = testZone->GetFilledPolysList( layer );
if( zoneOutline.Collide( &fill ) )
return true;
return true;
}
}