Lazily re-evaluate worst-clearance cache.

This prevents crashes when trying to re-evaluate
during destruction, etc. and is a cleaner solution
than trying to keep a flag updated.

It should also be a performance win for very large
documents.

Also implements proper threadlocking for the cache.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17950

(cherry picked from commit 498d2c9db1)
This commit is contained in:
Jeff Young 2024-05-15 14:08:31 +01:00
parent 882ff06e24
commit ba6fd2716e
2 changed files with 29 additions and 36 deletions

View File

@ -80,8 +80,6 @@ BOARD::BOARD() :
m_project( nullptr ),
m_userUnits( EDA_UNITS::MILLIMETRES ),
m_designSettings( new BOARD_DESIGN_SETTINGS( nullptr, "board.design_settings" ) ),
m_deleting( false ),
m_maxClearanceValue( 0 ),
m_NetInfo( this )
{
// A too small value do not allow connecting 2 shapes (i.e. segments) not exactly connected
@ -133,8 +131,6 @@ BOARD::BOARD() :
BOARD::~BOARD()
{
m_deleting = true;
// Untangle group parents before doing any deleting
for( PCB_GROUP* group : m_groups )
{
@ -258,8 +254,6 @@ void BOARD::IncrementTimeStamp()
{
m_timeStamp++;
UpdateMaxClearanceCache();
if( !m_IntersectsAreaCache.empty()
|| !m_EnclosedByAreaCache.empty()
|| !m_IntersectsCourtyardCache.empty()
@ -267,7 +261,8 @@ void BOARD::IncrementTimeStamp()
|| !m_IntersectsBCourtyardCache.empty()
|| !m_LayerExpressionCache.empty()
|| !m_ZoneBBoxCache.empty()
|| m_CopperItemRTreeCache )
|| m_CopperItemRTreeCache
|| m_maxClearanceValue.has_value() )
{
std::unique_lock<std::shared_mutex> writeLock( m_CachesMutex );
@ -290,6 +285,8 @@ void BOARD::IncrementTimeStamp()
m_DRCCopperZones.clear();
m_ZoneIsolatedIslandsMap.clear();
m_CopperZoneRTreeCache.clear();
m_maxClearanceValue.reset();
}
}
@ -778,30 +775,33 @@ BOARD_DESIGN_SETTINGS& BOARD::GetDesignSettings() const
}
void BOARD::UpdateMaxClearanceCache()
int BOARD::GetMaxClearanceValue() const
{
// in destructor, useless work
if( m_deleting )
return;
int worstClearance = m_designSettings->GetBiggestClearanceValue();
for( ZONE* zone : m_zones )
worstClearance = std::max( worstClearance, zone->GetLocalClearance() );
for( FOOTPRINT* footprint : m_footprints )
if( !m_maxClearanceValue.has_value() )
{
worstClearance = std::max( worstClearance, footprint->GetLocalClearance() );
std::unique_lock<std::shared_mutex> writeLock( m_CachesMutex );
for( PAD* pad : footprint->Pads() )
worstClearance = std::max( worstClearance, pad->GetLocalClearance() );
int worstClearance = m_designSettings->GetBiggestClearanceValue();
for( ZONE* zone : footprint->Zones() )
for( ZONE* zone : m_zones )
worstClearance = std::max( worstClearance, zone->GetLocalClearance() );
for( FOOTPRINT* footprint : m_footprints )
{
worstClearance = std::max( worstClearance, footprint->GetLocalClearance() );
for( PAD* pad : footprint->Pads() )
worstClearance = std::max( worstClearance, pad->GetLocalClearance() );
for( ZONE* zone : footprint->Zones() )
worstClearance = std::max( worstClearance, zone->GetLocalClearance() );
}
m_maxClearanceValue = worstClearance;
}
m_maxClearanceValue = worstClearance;
}
return m_maxClearanceValue.value_or( 0 );
};
void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter, const std::vector<ZONE*>& aZones )
@ -1120,6 +1120,7 @@ void BOARD::DeleteAllFootprints()
delete footprint;
m_footprints.clear();
IncrementTimeStamp();
}

View File

@ -1133,10 +1133,7 @@ public:
* the clearances from board design settings as well as embedded clearances in footprints,
* pads and zones. Includes electrical, physical, hole and edge clearances.
*/
int GetMaxClearanceValue() const
{
return m_maxClearanceValue;
};
int GetMaxClearanceValue() const;
/**
* Map all nets in the given board to nets with the same name (if any) in the destination
@ -1229,6 +1226,7 @@ public:
bool operator()( const BOARD_ITEM* aFirst, const BOARD_ITEM* aSecond ) const;
};
public:
// ------------ Run-time caches -------------
mutable std::shared_mutex m_CachesMutex;
std::unordered_map<PTR_PTR_CACHE_KEY, bool> m_IntersectsCourtyardCache;
@ -1240,6 +1238,7 @@ public:
std::unordered_map<ZONE*, std::unique_ptr<DRC_RTREE>> m_CopperZoneRTreeCache;
std::shared_ptr<DRC_RTREE> m_CopperItemRTreeCache;
mutable std::unordered_map<const ZONE*, BOX2I> m_ZoneBBoxCache;
mutable std::optional<int> m_maxClearanceValue;
// ------------ DRC caches -------------
std::vector<ZONE*> m_DRCZones;
@ -1263,14 +1262,10 @@ private:
( l->*aFunc )( std::forward<Args>( args )... );
}
void UpdateMaxClearanceCache();
friend class PCB_EDIT_FRAME;
/// the max distance between 2 end point to see them connected when building the board outlines
int m_outlinesChainingEpsilon;
int m_outlinesChainingEpsilon;
/// What is this board being used for
BOARD_USE m_boardUse;
@ -1320,9 +1315,6 @@ private:
*/
bool m_legacyTeardrops = false;
bool m_deleting; // inside destructor
int m_maxClearanceValue; // cached value
NETINFO_LIST m_NetInfo; // net info list (name, design constraints...
std::vector<BOARD_LISTENER*> m_listeners;