Skip to content
Permalink
Browse files
Optimise handling of rendered item results
While testing with a layer containing millions of annotations there was
some significant bottlenecks on the main thread during transfering
and cleaning up of rendered annotation item details. Optimise this
by storing results in separate vectors per map layer, so that
we can clear an entire vector when invalidating the results for
one layer instead of having to iterate over one combined
vector and remove items element-by-element.
  • Loading branch information
nyalldawson committed Sep 14, 2021
1 parent 48b7c3d commit 75c7b281680d54c6b75369c30875d42fbaa5f047
Showing with 35 additions and 29 deletions.
  1. +33 −28 src/core/maprenderer/qgsrendereditemresults.cpp
  2. +2 −1 src/core/maprenderer/qgsrendereditemresults.h
@@ -109,12 +109,13 @@ QgsRenderedItemResults::~QgsRenderedItemResults() = default;
QList<QgsRenderedItemDetails *> QgsRenderedItemResults::renderedItems() const
{
QList< QgsRenderedItemDetails * > res;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
res.reserve( static_cast< int >( mDetails.size() ) );
#else
res.reserve( mDetails.size() );
#endif
std::transform( mDetails.begin(), mDetails.end(), std::back_inserter( res ), []( const auto & detail ) {return detail.get();} );
for ( const auto &it : mDetails )
{
std::transform( it.second.begin(), it.second.end(), std::back_inserter( res ), []( const auto & detail )
{
return detail.get();
} );
}
return res;
}

@@ -148,53 +149,57 @@ void QgsRenderedItemResults::appendResults( const QList<QgsRenderedItemDetails *
if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( details ) )
mAnnotationItemsIndex->insert( annotationDetails, annotationDetails->boundingBox() );

mDetails.emplace_back( std::unique_ptr< QgsRenderedItemDetails >( details ) );

mDetails[ details->layerId() ].emplace_back( std::unique_ptr< QgsRenderedItemDetails >( details ) );
}
}

void QgsRenderedItemResults::transferResults( QgsRenderedItemResults *other, const QStringList &layerIds )
{
for ( auto it = other->mDetails.begin(); it != other->mDetails.end(); )
for ( const QString &layerId : layerIds )
{
if ( layerIds.contains( ( *it )->layerId() ) )
auto otherLayerIt = other->mDetails.find( layerId );
if ( otherLayerIt == other->mDetails.end() )
continue;

std::vector< std::unique_ptr< QgsRenderedItemDetails > > &source = otherLayerIt->second;

for ( std::unique_ptr< QgsRenderedItemDetails > &details : source )
{
if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( ( *it ).get() ) )
if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( details.get() ) )
mAnnotationItemsIndex->insert( annotationDetails, annotationDetails->boundingBox() );

mDetails.emplace_back( std::move( *it ) );
other->mDetails.erase( it );
}
else
{
it++;
mDetails[layerId].emplace_back( std::move( details ) );
}

other->mDetails.erase( otherLayerIt );
}
}

void QgsRenderedItemResults::transferResults( QgsRenderedItemResults *other )
{
for ( auto it = other->mDetails.begin(); it != other->mDetails.end(); ++it )
for ( auto layerIt = other->mDetails.begin(); layerIt != other->mDetails.end(); ++layerIt )
{
if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( ( *it ).get() ) )
mAnnotationItemsIndex->insert( annotationDetails, annotationDetails->boundingBox() );
std::vector< std::unique_ptr< QgsRenderedItemDetails > > &dest = mDetails[layerIt->first];
dest.reserve( layerIt->second.size() );
for ( auto it = layerIt->second.begin(); it != layerIt->second.end(); ++it )
{
if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( ( *it ).get() ) )
mAnnotationItemsIndex->insert( annotationDetails, annotationDetails->boundingBox() );

mDetails.emplace_back( std::move( *it ) );
dest.emplace_back( std::move( *it ) );
}
}
other->mDetails.clear();
}

void QgsRenderedItemResults::eraseResultsFromLayers( const QStringList &layerIds )
{
for ( auto it = mDetails.begin(); it != mDetails.end(); )
for ( const QString &layerId : layerIds )
{
if ( layerIds.contains( ( *it )->layerId() ) )
{
auto it = mDetails.find( layerId );
if ( it != mDetails.end() )
mDetails.erase( it );
}
else
{
it++;
}
}
}

@@ -24,6 +24,7 @@
#include <memory>
#include <QList>
#include <vector>
#include <unordered_map>

class QgsRenderedItemDetails;
class QgsRenderContext;
@@ -109,7 +110,7 @@ class CORE_EXPORT QgsRenderedItemResults

QgsRectangle mExtent;

std::vector< std::unique_ptr< QgsRenderedItemDetails > > mDetails;
std::unordered_map< QString, std::vector< std::unique_ptr< QgsRenderedItemDetails > > > mDetails;
std::unique_ptr< QgsRenderedItemResultsSpatialIndex > mAnnotationItemsIndex;

};

0 comments on commit 75c7b28

Please sign in to comment.