[core] Synchronize state of CollisionIndex and FeatureIndexes.
Fixes issue #10778, in which mismatch between FeatureIndex and CollisionIndex could lead to inconsistent results or even invalid array access.
This commit is contained in:
@@ -389,6 +389,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
|
||||
}
|
||||
|
||||
placementChanged = newPlacement->commit(*placement, parameters.timePoint);
|
||||
// commitFeatureIndexes depends on the assumption that no new FeatureIndex has been loaded since placement
|
||||
// started. If we violate this assumption, then we need to either make CollisionIndex completely independendent of
|
||||
// FeatureIndex, or find a way for its entries to point to multiple FeatureIndexes.
|
||||
commitFeatureIndexes();
|
||||
if (placementChanged || symbolBucketsChanged) {
|
||||
placement = std::move(newPlacement);
|
||||
}
|
||||
@@ -768,6 +772,15 @@ bool Renderer::Impl::hasTransitions(TimePoint timePoint) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Renderer::Impl::commitFeatureIndexes() {
|
||||
for (auto& source : renderSources) {
|
||||
for (auto& renderTile : source.second->getRenderTiles()) {
|
||||
Tile& tile = renderTile.get().tile;
|
||||
tile.commitFeatureIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::Impl::updateFadingTiles() {
|
||||
fadingTiles = false;
|
||||
for (auto& source : renderSources) {
|
||||
|
||||
@@ -74,6 +74,7 @@ private:
|
||||
void onTileChanged(RenderSource&, const OverscaledTileID&) override;
|
||||
void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
|
||||
|
||||
void commitFeatureIndexes();
|
||||
void updateFadingTiles();
|
||||
|
||||
friend class Renderer;
|
||||
|
||||
@@ -130,7 +130,7 @@ void GeometryTile::onLayout(LayoutResult result, const uint64_t resultCorrelatio
|
||||
// replacing a tile at a different zoom that _did_ have symbols.
|
||||
(void)resultCorrelationID;
|
||||
nonSymbolBuckets = std::move(result.nonSymbolBuckets);
|
||||
featureIndex = std::move(result.featureIndex);
|
||||
pendingFeatureIndex = std::move(result.featureIndex);
|
||||
data = std::move(result.tileData);
|
||||
observer->onTileChanged(*this);
|
||||
}
|
||||
@@ -213,6 +213,12 @@ Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const {
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
void GeometryTile::commitFeatureIndex() {
|
||||
if (pendingFeatureIndex) {
|
||||
featureIndex = std::move(pendingFeatureIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryTile::queryRenderedFeatures(
|
||||
std::unordered_map<std::string, std::vector<Feature>>& result,
|
||||
const GeometryCoordinates& queryGeometry,
|
||||
|
||||
@@ -100,6 +100,8 @@ public:
|
||||
void markRenderedPreviously() override;
|
||||
void performedFadePlacement() override;
|
||||
|
||||
void commitFeatureIndex() override;
|
||||
|
||||
protected:
|
||||
const GeometryTileData* getData() {
|
||||
return data.get();
|
||||
@@ -123,6 +125,7 @@ private:
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<Bucket>> nonSymbolBuckets;
|
||||
std::unique_ptr<FeatureIndex> featureIndex;
|
||||
std::unique_ptr<FeatureIndex> pendingFeatureIndex;
|
||||
std::unique_ptr<const GeometryTileData> data;
|
||||
|
||||
optional<AlphaImage> glyphAtlasImage;
|
||||
|
||||
@@ -109,6 +109,11 @@ public:
|
||||
// and will have time to finish by the second placement.
|
||||
virtual void performedFadePlacement() {}
|
||||
|
||||
// FeatureIndexes are loaded asynchronously, but must be used with a CollisionIndex
|
||||
// generated from the same data. Calling commitFeatureIndex signals the current
|
||||
// CollisionIndex is up-to-date and allows us to start using the last loaded FeatureIndex
|
||||
virtual void commitFeatureIndex() {}
|
||||
|
||||
void dumpDebugLogs() const;
|
||||
|
||||
const OverscaledTileID id;
|
||||
|
||||
Reference in New Issue
Block a user