Performance

Cache VIEW_ITEM's bbox in VIEW_TREE for faster removals.

Fixes https://gitlab.com/kicad/code/kicad/issues/16841
This commit is contained in:
Yon Uriarte 2024-02-13 09:53:35 +01:00 committed by Jeff Young
parent 0129191ec0
commit 464f185387
3 changed files with 39 additions and 12 deletions

View File

@ -234,6 +234,8 @@ private:
int m_groupsSize; int m_groupsSize;
std::vector<int> m_layers; /// Stores layer numbers used by the item. std::vector<int> m_layers; /// Stores layer numbers used by the item.
BOX2I m_bbox; /// Cached inserted Bbox for faster removals.
}; };
@ -326,6 +328,8 @@ void VIEW::Add( VIEW_ITEM* aItem, int aDrawPriority )
aItem->m_viewPrivData->m_view = this; aItem->m_viewPrivData->m_view = this;
aItem->m_viewPrivData->m_drawPriority = aDrawPriority; aItem->m_viewPrivData->m_drawPriority = aDrawPriority;
const BOX2I bbox = aItem->ViewBBox();
aItem->m_viewPrivData->m_bbox = bbox;
aItem->ViewGetLayers( layers, layers_count ); aItem->ViewGetLayers( layers, layers_count );
aItem->viewPrivData()->saveLayers( layers, layers_count ); aItem->viewPrivData()->saveLayers( layers, layers_count );
@ -338,7 +342,7 @@ void VIEW::Add( VIEW_ITEM* aItem, int aDrawPriority )
continue, wxS( "Invalid layer" ) ); continue, wxS( "Invalid layer" ) );
VIEW_LAYER& l = m_layers[layers[i]]; VIEW_LAYER& l = m_layers[layers[i]];
l.items->Insert( aItem ); l.items->Insert( aItem, bbox );
MarkTargetDirty( l.target ); MarkTargetDirty( l.target );
} }
@ -362,11 +366,12 @@ void VIEW::Remove( VIEW_ITEM* aItem )
int layers[VIEW::VIEW_MAX_LAYERS], layers_count; int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
aItem->m_viewPrivData->getLayers( layers, layers_count ); aItem->m_viewPrivData->getLayers( layers, layers_count );
const BOX2I* bbox = &aItem->m_viewPrivData->m_bbox;
for( int i = 0; i < layers_count; ++i ) for( int i = 0; i < layers_count; ++i )
{ {
VIEW_LAYER& l = m_layers[layers[i]]; VIEW_LAYER& l = m_layers[layers[i]];
l.items->Remove( aItem ); l.items->Remove( aItem, bbox );
MarkTargetDirty( l.target ); MarkTargetDirty( l.target );
// Clear the GAL cache // Clear the GAL cache
@ -1327,12 +1332,17 @@ void VIEW::updateBbox( VIEW_ITEM* aItem )
int layers[VIEW_MAX_LAYERS], layers_count; int layers[VIEW_MAX_LAYERS], layers_count;
aItem->ViewGetLayers( layers, layers_count ); aItem->ViewGetLayers( layers, layers_count );
wxASSERT( aItem->m_viewPrivData ); //must have a viewPrivData
const BOX2I new_bbox = aItem->ViewBBox();
const BOX2I* old_bbox = &aItem->m_viewPrivData->m_bbox;
aItem->m_viewPrivData->m_bbox = new_bbox;
for( int i = 0; i < layers_count; ++i ) for( int i = 0; i < layers_count; ++i )
{ {
VIEW_LAYER& l = m_layers[layers[i]]; VIEW_LAYER& l = m_layers[layers[i]];
l.items->Remove( aItem ); l.items->Remove( aItem, old_bbox );
l.items->Insert( aItem ); l.items->Insert( aItem, new_bbox );
MarkTargetDirty( l.target ); MarkTargetDirty( l.target );
} }
} }
@ -1348,11 +1358,12 @@ void VIEW::updateLayers( VIEW_ITEM* aItem )
// Remove the item from previous layer set // Remove the item from previous layer set
viewData->getLayers( layers, layers_count ); viewData->getLayers( layers, layers_count );
const BOX2I* old_bbox = &aItem->m_viewPrivData->m_bbox;
for( int i = 0; i < layers_count; ++i ) for( int i = 0; i < layers_count; ++i )
{ {
VIEW_LAYER& l = m_layers[layers[i]]; VIEW_LAYER& l = m_layers[layers[i]];
l.items->Remove( aItem ); l.items->Remove( aItem, old_bbox );
MarkTargetDirty( l.target ); MarkTargetDirty( l.target );
if( IsCached( l.id ) ) if( IsCached( l.id ) )
@ -1368,6 +1379,9 @@ void VIEW::updateLayers( VIEW_ITEM* aItem )
} }
} }
const BOX2I new_bbox = aItem->ViewBBox();
aItem->m_viewPrivData->m_bbox = new_bbox;
// Add the item to new layer set // Add the item to new layer set
aItem->ViewGetLayers( layers, layers_count ); aItem->ViewGetLayers( layers, layers_count );
viewData->saveLayers( layers, layers_count ); viewData->saveLayers( layers, layers_count );
@ -1375,7 +1389,7 @@ void VIEW::updateLayers( VIEW_ITEM* aItem )
for( int i = 0; i < layers_count; i++ ) for( int i = 0; i < layers_count; i++ )
{ {
VIEW_LAYER& l = m_layers[layers[i]]; VIEW_LAYER& l = m_layers[layers[i]];
l.items->Insert( aItem ); l.items->Insert( aItem, new_bbox );
MarkTargetDirty( l.target ); MarkTargetDirty( l.target );
} }
} }
@ -1463,6 +1477,9 @@ void VIEW::UpdateItems()
// and re-insert items from scratch // and re-insert items from scratch
for( VIEW_ITEM* item : allItems ) for( VIEW_ITEM* item : allItems )
{ {
const BOX2I bbox = item->ViewBBox();
item->m_viewPrivData->m_bbox = bbox;
item->ViewGetLayers( layers, layers_count ); item->ViewGetLayers( layers, layers_count );
item->viewPrivData()->saveLayers( layers, layers_count ); item->viewPrivData()->saveLayers( layers, layers_count );
@ -1471,7 +1488,7 @@ void VIEW::UpdateItems()
wxCHECK2_MSG( layers[i] >= 0 && static_cast<unsigned>( layers[i] ) < m_layers.size(), wxCHECK2_MSG( layers[i] >= 0 && static_cast<unsigned>( layers[i] ) < m_layers.size(),
continue, wxS( "Invalid layer" ) ); continue, wxS( "Invalid layer" ) );
VIEW_LAYER& l = m_layers[layers[i]]; VIEW_LAYER& l = m_layers[layers[i]];
l.items->Insert( item ); l.items->Insert( item, bbox );
MarkTargetDirty( l.target ); MarkTargetDirty( l.target );
} }

View File

@ -30,6 +30,7 @@
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <core/arraydim.h> #include <core/arraydim.h>
#include <core/profile.h>
/** /**
@ -97,8 +98,10 @@ GERBER_FILE_IMAGE::GERBER_FILE_IMAGE( int aLayer ) :
GERBER_FILE_IMAGE::~GERBER_FILE_IMAGE() GERBER_FILE_IMAGE::~GERBER_FILE_IMAGE()
{ {
for( GERBER_DRAW_ITEM* item : GetItems() ) // Reverse iteration to avoid O(N^2) memcpy in a vector erase downstream.
delete item; // It results in a O(N^2) std::find, which is somewhat faster.
for( auto it = GetItems().rbegin(); it < GetItems().rend(); it++ )
delete *it;
m_drawings.clear(); m_drawings.clear();

View File

@ -46,9 +46,8 @@ public:
* *
* Item's bounding box is taken via its ViewBBox() method. * Item's bounding box is taken via its ViewBBox() method.
*/ */
void Insert( VIEW_ITEM* aItem ) void Insert( VIEW_ITEM* aItem, const BOX2I& bbox )
{ {
const BOX2I& bbox = aItem->ViewBBox();
const int mmin[2] = { bbox.GetX(), bbox.GetY() }; const int mmin[2] = { bbox.GetX(), bbox.GetY() };
const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() }; const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
@ -60,10 +59,18 @@ public:
* *
* Removal is done by comparing pointers, attempting to remove a copy of the item will fail. * Removal is done by comparing pointers, attempting to remove a copy of the item will fail.
*/ */
void Remove( VIEW_ITEM* aItem ) void Remove( VIEW_ITEM* aItem, const BOX2I* aBbox )
{ {
// const BOX2I& bbox = aItem->ViewBBox(); // const BOX2I& bbox = aItem->ViewBBox();
if( aBbox )
{
const int mmin[2] = { aBbox->GetX(), aBbox->GetY() };
const int mmax[2] = { aBbox->GetRight(), aBbox->GetBottom() };
VIEW_RTREE_BASE::Remove( mmin, mmax, aItem );
return;
}
// FIXME: use cached bbox or ptr_map to speed up pointer <-> node lookups. // FIXME: use cached bbox or ptr_map to speed up pointer <-> node lookups.
const int mmin[2] = { INT_MIN, INT_MIN }; const int mmin[2] = { INT_MIN, INT_MIN };
const int mmax[2] = { INT_MAX, INT_MAX }; const int mmax[2] = { INT_MAX, INT_MAX };