diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index 883382b20..c143691c0 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -181,7 +181,7 @@ protected: bool is3D = false; bool isCustom = false; std::string name; - util::SimpleIdentity uniqueID; + const util::SimpleIdentity uniqueID; gfx::ShaderProgramBasePtr shader; mbgl::RenderPass renderPass; std::optional tileID; @@ -203,7 +203,7 @@ using UniqueDrawable = std::unique_ptr; /// Comparator for sorting drawable pointers primarily by draw priority struct DrawableLessByPriority { - DrawableLessByPriority(bool descending) + DrawableLessByPriority(bool descending = false) : desc(descending) {} bool operator()(const Drawable& left, const Drawable& right) const { const auto& a = desc ? right : left; @@ -213,6 +213,8 @@ struct DrawableLessByPriority { } return a.getId() < b.getId(); } + bool operator()(const Drawable* left, const Drawable* right) const { return operator()(*left, *right); } + bool operator()(const UniqueDrawable& left, const UniqueDrawable& right) const { return operator()(*left, *right); } bool operator()(const DrawablePtr& left, const DrawablePtr& right) const { const auto& a = desc ? right : left; const auto& b = desc ? left : right; diff --git a/include/mbgl/renderer/layer_group.hpp b/include/mbgl/renderer/layer_group.hpp index d29b5bdf2..b8f8de9de 100644 --- a/include/mbgl/renderer/layer_group.hpp +++ b/include/mbgl/renderer/layer_group.hpp @@ -66,12 +66,14 @@ public: /// Called at the end of each frame virtual void postRender(RenderOrchestrator&, PaintParameters&) {} - /// Call the provided function for each drawable in undefined order - virtual void observeDrawables(std::function) = 0; - virtual void observeDrawables(std::function) const = 0; + /// Call the provided function for each drawable in priority order + virtual void observeDrawables(const std::function&&) = 0; + virtual void observeDrawables(const std::function&&) const = 0; - /// Call the provided function for each drawable in undefined order, allowing ownership to be taken. - virtual void observeDrawables(std::function) = 0; + /// Call the provided function for each drawable in undefined order, allowing for removal. + /// @param f A function called with each drawable, returning true to keep and false to discard it. + /// @return The number of items removed + virtual std::size_t observeDrawablesRemove(const std::function&& f) = 0; /// Attach a tweaker to be run on this layer group for each frame void setLayerTweaker(LayerTweakerPtr tweaker) { layerTweaker = std::move(tweaker); } @@ -100,13 +102,15 @@ public: std::vector removeDrawables(mbgl::RenderPass, const OverscaledTileID&); void addDrawable(mbgl::RenderPass, const OverscaledTileID&, gfx::UniqueDrawable&&); - void observeDrawables(std::function) override; - void observeDrawables(std::function) const override; - void observeDrawables(std::function) override; + void observeDrawables(const std::function&&) override; + void observeDrawables(const std::function&&) const override; + std::size_t observeDrawablesRemove(const std::function&&) override; /// Call the provided function for each drawable for the given tile - void observeDrawables(mbgl::RenderPass, const OverscaledTileID&, std::function&&); - void observeDrawables(mbgl::RenderPass, const OverscaledTileID&, std::function&&) const; + void observeDrawables(mbgl::RenderPass, const OverscaledTileID&, const std::function&&); + void observeDrawables(mbgl::RenderPass, + const OverscaledTileID&, + const std::function&&) const; std::size_t clearDrawables() override; @@ -129,9 +133,9 @@ public: std::vector removeDrawables(mbgl::RenderPass); void addDrawable(gfx::UniqueDrawable&&); - void observeDrawables(std::function) override; - void observeDrawables(std::function) const override; - void observeDrawables(std::function) override; + void observeDrawables(const std::function&&) override; + void observeDrawables(const std::function&&) const override; + std::size_t observeDrawablesRemove(const std::function&&) override; std::size_t clearDrawables() override; diff --git a/src/mbgl/renderer/layer_group.cpp b/src/mbgl/renderer/layer_group.cpp index 08bd2e242..fbf15a6f2 100644 --- a/src/mbgl/renderer/layer_group.cpp +++ b/src/mbgl/renderer/layer_group.cpp @@ -4,20 +4,18 @@ #include #include -#include +#include namespace mbgl { struct LayerGroup::Impl { - Impl(std::size_t capacity) { drawables.reserve(capacity); } - - using DrawableCollection = std::vector; + using DrawableCollection = std::set; DrawableCollection drawables; }; -LayerGroup::LayerGroup(int32_t layerIndex_, std::size_t initialCapacity, std::string name_) +LayerGroup::LayerGroup(int32_t layerIndex_, std::size_t /*initialCapacity*/, std::string name_) : LayerGroupBase(layerIndex_, std::move(name_)), - impl(std::make_unique(initialCapacity)) {} + impl(std::make_unique()) {} LayerGroup::~LayerGroup() = default; @@ -26,10 +24,10 @@ std::size_t LayerGroup::getDrawableCount() const { } void LayerGroup::addDrawable(gfx::UniqueDrawable&& drawable) { - impl->drawables.emplace_back(std::move(drawable)); + impl->drawables.emplace(std::move(drawable)); } -void LayerGroup::observeDrawables(std::function f) { +void LayerGroup::observeDrawables(const std::function&& f) { for (const auto& item : impl->drawables) { if (item) { f(*item); @@ -37,7 +35,7 @@ void LayerGroup::observeDrawables(std::function f) { } } -void LayerGroup::observeDrawables(std::function f) const { +void LayerGroup::observeDrawables(const std::function&& f) const { for (const auto& item : impl->drawables) { if (item) { f(*item); @@ -45,20 +43,20 @@ void LayerGroup::observeDrawables(std::function f) c } } -void LayerGroup::observeDrawables(std::function f) { - for (auto i = impl->drawables.begin(); i != impl->drawables.end();) { - auto& drawable = *i; - if (drawable) { - f(drawable); - } - if (drawable) { - // Not removed, keep going - ++i; - } else { - // Removed, take it out of the map - i = impl->drawables.erase(i); +std::size_t LayerGroup::observeDrawablesRemove(const std::function&& f) { + decltype(impl->drawables) newSet; + const auto oldSize = impl->drawables.size(); + while (!impl->drawables.empty()) { + // set members are immutable, since changes could affect its position, so extract each item + gfx::UniqueDrawable drawable = std::move(impl->drawables.extract(impl->drawables.begin()).value()); + if (f(*drawable)) { + // Not removed, keep it, but in a new set so that if the key value + // has increased, we don't see it again during this iteration. + newSet.emplace_hint(newSet.end(), std::move(drawable)); } } + std::swap(impl->drawables, newSet); + return (oldSize - impl->drawables.size()); } std::size_t LayerGroup::clearDrawables() { diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 0cf966cce..caed90c78 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -203,6 +203,10 @@ void RenderBackgroundLayer::prepare(const LayerPrepareParameters& params) { addPatternIfNeeded(evaluated.get().from.id(), params); addPatternIfNeeded(evaluated.get().to.id(), params); } + +#if MLN_DRAWABLE_RENDERER + updateRenderTileIDs(); +#endif // MLN_DRAWABLE_RENDERER } #if MLN_DRAWABLE_RENDERER @@ -275,21 +279,11 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders, const auto indexes = RenderStaticData::quadTriangleIndices(); const auto segs = RenderStaticData::tileTriangleSegments(); - // Put the tile cover into a searchable form. - // TODO: Likely better to sort and `std::binary_search` the vector. - // If it's returned in a well-defined order, we might not even need to sort. - const std::unordered_set newTileIDs(tileCover.begin(), tileCover.end()); - std::unique_ptr builder; - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + tileLayerGroup->observeDrawables([&](gfx::Drawable& drawable) -> bool { // Has this tile dropped out of the cover set? - const auto tileID = drawable->getTileID(); - if (tileID && newTileIDs.find(*tileID) == newTileIDs.end()) { - drawable.reset(); - ++stats.drawablesRemoved; - return; - } + return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); }); // For each tile in the cover set, add a tile drawable if one doesn't already exist. diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index 1ce33aa21..5f86ff132 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -300,28 +300,17 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, return; } - std::unordered_set newTileIDs(renderTiles->size()); - std::transform(renderTiles->begin(), - renderTiles->end(), - std::inserter(newTileIDs, newTileIDs.begin()), - [](const auto& renderTile) -> OverscaledTileID { return renderTile.get().getOverscaledTileID(); }); - std::unique_ptr circleBuilder; std::vector newTiles; gfx::VertexAttributeArray circleVertexAttrs; - auto renderPass = RenderPass::Translucent; + constexpr auto renderPass = RenderPass::Translucent; if (!(mbgl::underlying_type(renderPass) & evaluatedProperties->renderPasses)) { return; } - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { - const auto tileID = drawable->getTileID(); - if (tileID && newTileIDs.find(*tileID) == newTileIDs.end()) { - // remove it - drawable.reset(); - ++stats.drawablesRemoved; - } + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { + return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); }); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index 216ec1780..374bc1c82 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -92,14 +92,6 @@ bool RenderFillExtrusionLayer::is3D() const { return true; } -void RenderFillExtrusionLayer::prepare(const LayerPrepareParameters& params) { - RenderLayer::prepare(params); - -#if MLN_DRAWABLE_RENDERER - updateRenderTileIDs(); -#endif // MLN_DRAWABLE_RENDERER -} - #if MLN_LEGACY_RENDERER void RenderFillExtrusionLayer::render(PaintParameters& parameters) { assert(renderTiles); @@ -315,13 +307,10 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, // in the "3D pass". constexpr auto drawPass = RenderPass::Translucent; - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. - const auto tileID = drawable->getTileID(); - if (drawable->getRenderPass() != drawPass || (tileID && renderTileIDs.find(*tileID) == renderTileIDs.end())) { - drawable.reset(); - ++stats.drawablesRemoved; - } + return (drawable.getRenderPass() == drawPass && + (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end())); }); const auto zoom = static_cast(state.getZoom()); diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp index 213da6a7f..c0f19017c 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp @@ -23,7 +23,6 @@ private: bool hasTransition() const override; bool hasCrossfade() const override; bool is3D() const override; - void prepare(const LayerPrepareParameters&) override; #if MLN_LEGACY_RENDERER void render(PaintParameters&) override; diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 7464d7ac0..a9b0d2888 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -325,12 +325,6 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, return; } - std::unordered_set newTileIDs(renderTiles->size()); - std::transform(renderTiles->begin(), - renderTiles->end(), - std::inserter(newTileIDs, newTileIDs.begin()), - [](const auto& renderTile) -> OverscaledTileID { return renderTile.get().getOverscaledTileID(); }); - std::unique_ptr fillBuilder; std::unique_ptr outlineBuilder; std::unique_ptr patternBuilder; @@ -364,13 +358,10 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, builder.setEnableStencil(true); }; - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. - const auto tileID = drawable->getTileID(); - if (drawable->getRenderPass() != renderPass || (tileID && newTileIDs.find(*tileID) == newTileIDs.end())) { - drawable.reset(); - ++stats.drawablesRemoved; - } + return (drawable.getRenderPass() == renderPass && + (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end())); }); for (const RenderTile& tile : *renderTiles) { diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index ba61a94f2..9d345478c 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -317,12 +317,6 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, return; } - std::unordered_set newTileIDs(renderTiles->size()); - std::transform(renderTiles->begin(), - renderTiles->end(), - std::inserter(newTileIDs, newTileIDs.begin()), - [](const auto& renderTile) -> OverscaledTileID { return renderTile.get().getOverscaledTileID(); }); - std::unique_ptr heatmapBuilder; std::vector newTiles; gfx::VertexAttributeArray heatmapVertexAttrs; @@ -332,13 +326,8 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, return; } - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { - const auto tileID = drawable->getTileID(); - if (tileID && newTileIDs.find(*tileID) == newTileIDs.end()) { - // remove it - drawable.reset(); - ++stats.drawablesRemoved; - } + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { + return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); }); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 417aa6357..a7276f019 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -90,7 +90,7 @@ void RenderLineLayer::prepare(const LayerPrepareParameters& params) { const auto& evaluated = getEvaluated(renderData->layerProperties); if (evaluated.get().from.empty()) continue; - auto& bucket = static_cast(*renderData->bucket); + const auto& bucket = static_cast(*renderData->bucket); const LinePatternCap cap = bucket.layout.get() == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; // Ensures that the dash data gets added to the atlas. @@ -441,22 +441,13 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, lineSDFShaderGroup = shaders.getShaderGroup("LineSDFShader"); } - std::unordered_set newTileIDs(renderTiles->size()); - std::transform(renderTiles->begin(), - renderTiles->end(), - std::inserter(newTileIDs, newTileIDs.begin()), - [](const auto& renderTile) -> OverscaledTileID { return renderTile.get().getOverscaledTileID(); }); - const RenderPass renderPass = static_cast(evaluatedProperties->renderPasses & ~mbgl::underlying_type(RenderPass::Opaque)); - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. - const auto tileID = drawable->getTileID(); - if (drawable->getRenderPass() != renderPass || (tileID && newTileIDs.find(*tileID) == newTileIDs.end())) { - drawable.reset(); - ++stats.drawablesRemoved; - } + return (drawable.getRenderPass() == renderPass && + (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end())); }); auto createLineBuilder = [&](const std::string& name, diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index e8d6c10f9..7a77f44dd 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -97,6 +97,10 @@ void RenderRasterLayer::prepare(const LayerPrepareParameters& params) { imageData = params.source->getImageRenderData(); // It is possible image data is not available until the source loads it. assert(renderTiles || imageData || !params.source->isEnabled()); + +#if MLN_DRAWABLE_RENDERER + updateRenderTileIDs(); +#endif // MLN_DRAWABLE_RENDERER } #if MLN_LEGACY_RENDERER @@ -416,19 +420,9 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, } } else if (renderTiles) { if (layerGroup) { - layerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + stats.drawablesRemoved += layerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // Has this tile dropped out of the cover set? - if (const auto it = std::find_if(renderTiles->begin(), - renderTiles->end(), - [&drawable](const auto& renderTile) { - return drawable->getTileID() == - renderTile.get().getOverscaledTileID(); - }); - it == renderTiles->end()) { - // remove it - drawable.reset(); - ++stats.drawablesRemoved; - } + return (!drawable.getTileID() || renderTileIDs.find(*drawable.getTileID()) != renderTileIDs.end()); }); } else { // Set up a tile layer group diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 3752f6803..451f16f01 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -831,14 +831,14 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, } auto* tileLayerGroup = static_cast(layerGroup.get()); - tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + stats.drawablesRemoved += tileLayerGroup->observeDrawablesRemove([&](gfx::Drawable& drawable) { // If the render pass has changed or the tile has dropped out of the cover set, remove it. - const auto tileID = drawable->getTileID(); - if (drawable->getRenderPass() != passes || (tileID && renderTileIDs.find(*tileID) == renderTileIDs.end())) { - drawable.reset(); + const auto& tileID = drawable.getTileID(); + if (drawable.getRenderPass() != passes || (tileID && renderTileIDs.find(*tileID) == renderTileIDs.end())) { tileBucketInstances.erase(*tileID); - ++stats.drawablesRemoved; + return false; } + return true; }); const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get().isUndefined(); diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 40fcd1fdc..477afe74c 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -58,6 +58,10 @@ void RenderLayer::prepare(const LayerPrepareParameters& params) { assert(params.source->isEnabled()); renderTiles = params.source->getRenderTiles(); addRenderPassesFromTiles(); + +#if MLN_DRAWABLE_RENDERER + updateRenderTileIDs(); +#endif // MLN_DRAWABLE_RENDERER } std::optional RenderLayer::getSolidBackground() const { diff --git a/src/mbgl/renderer/tile_layer_group.cpp b/src/mbgl/renderer/tile_layer_group.cpp index 01408c2e9..f463ea84c 100644 --- a/src/mbgl/renderer/tile_layer_group.cpp +++ b/src/mbgl/renderer/tile_layer_group.cpp @@ -5,6 +5,7 @@ #include #include +#include namespace mbgl { @@ -22,11 +23,14 @@ struct TileLayerGroupTileKey { }; struct TileLayerGroup::Impl { - Impl(std::size_t capacity) - : tileDrawables(capacity) {} + Impl(std::size_t initialCapacity) + : drawablesByTile(initialCapacity) {} using TileMap = std::unordered_multimap; - TileMap tileDrawables; + TileMap drawablesByTile; + + using DrawableMap = std::set; + DrawableMap sortedDrawables; }; LayerGroupBase::LayerGroupBase(int32_t layerIndex_, std::string name_) @@ -40,80 +44,97 @@ TileLayerGroup::TileLayerGroup(int32_t layerIndex_, std::size_t initialCapacity, TileLayerGroup::~TileLayerGroup() = default; std::size_t TileLayerGroup::getDrawableCount() const { - return impl->tileDrawables.size(); + return impl->drawablesByTile.size(); } static const gfx::UniqueDrawable no_tile; std::size_t TileLayerGroup::getDrawableCount(mbgl::RenderPass pass, const OverscaledTileID& id) const { - const auto range = impl->tileDrawables.equal_range({pass, id}); + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); + const auto range = impl->drawablesByTile.equal_range({pass, id}); return std::distance(range.first, range.second); } std::vector TileLayerGroup::removeDrawables(mbgl::RenderPass pass, const OverscaledTileID& id) { - const auto range = impl->tileDrawables.equal_range({pass, id}); + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); + const auto range = impl->drawablesByTile.equal_range({pass, id}); std::vector result(std::distance(range.first, range.second)); std::transform( std::make_move_iterator(range.first), std::make_move_iterator(range.second), result.begin(), [](auto&& pair) { return std::move(pair.second); }); - impl->tileDrawables.erase(range.first, range.second); + impl->drawablesByTile.erase(range.first, range.second); + std::for_each(result.begin(), result.end(), [&](const auto& item) { + const auto hit = impl->sortedDrawables.find(item.get()); + assert(hit != impl->sortedDrawables.end()); + if (hit != impl->sortedDrawables.end()) { + impl->sortedDrawables.erase(hit); + } + }); return result; } void TileLayerGroup::addDrawable(mbgl::RenderPass pass, const OverscaledTileID& id, gfx::UniqueDrawable&& drawable) { - impl->tileDrawables.insert(std::make_pair(TileLayerGroupTileKey{pass, id}, std::move(drawable))); -} - -void TileLayerGroup::observeDrawables(std::function f) { - for (auto& pair : impl->tileDrawables) { - if (pair.second) { - f(*pair.second); - } + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); + if (drawable) { + [[maybe_unused]] const auto result = impl->sortedDrawables.insert(drawable.get()); + assert(result.second); + impl->drawablesByTile.insert(std::make_pair(TileLayerGroupTileKey{pass, id}, std::move(drawable))); } } -void TileLayerGroup::observeDrawables(std::function f) const { - for (const auto& pair : impl->tileDrawables) { - if (pair.second) { - f(*pair.second); - } +void TileLayerGroup::observeDrawables(const std::function&& f) { + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); + for (auto* drawable : impl->sortedDrawables) { + f(*drawable); } } -void TileLayerGroup::observeDrawables(std::function f) { - for (auto i = impl->tileDrawables.begin(); i != impl->tileDrawables.end();) { +void TileLayerGroup::observeDrawables(const std::function&& f) const { + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); + for (const auto* drawable : impl->sortedDrawables) { + f(*drawable); + } +} + +std::size_t TileLayerGroup::observeDrawablesRemove(const std::function&& f) { + const auto oldSize = impl->drawablesByTile.size(); + for (auto i = impl->drawablesByTile.begin(); i != impl->drawablesByTile.end();) { auto& drawable = i->second; - if (drawable) { - f(drawable); - } - if (drawable) { + if (f(*drawable)) { // Not removed, keep going ++i; } else { - // Removed, take it out of the map - i = impl->tileDrawables.erase(i); + // Removed, take it out of the collections + impl->sortedDrawables.erase(drawable.get()); + i = impl->drawablesByTile.erase(i); } + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); } + return (oldSize - impl->drawablesByTile.size()); } void TileLayerGroup::observeDrawables(mbgl::RenderPass pass, const OverscaledTileID& tileID, - std::function&& f) { - const auto range = impl->tileDrawables.equal_range({pass, tileID}); + const std::function&& f) { + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); + const auto range = impl->drawablesByTile.equal_range({pass, tileID}); std::for_each(range.first, range.second, [&f](const auto& pair) { f(*pair.second); }); } void TileLayerGroup::observeDrawables(mbgl::RenderPass pass, const OverscaledTileID& tileID, - std::function&& f) const { - const auto range = impl->tileDrawables.equal_range({pass, tileID}); + const std::function&& f) const { + assert(impl->drawablesByTile.size() == impl->sortedDrawables.size()); + const auto range = impl->drawablesByTile.equal_range({pass, tileID}); std::for_each(range.first, range.second, [&f](const auto& pair) { f(*pair.second); }); } std::size_t TileLayerGroup::clearDrawables() { - const auto count = impl->tileDrawables.size(); - impl->tileDrawables.clear(); + const auto count = impl->drawablesByTile.size(); + assert(count == impl->sortedDrawables.size()); + impl->sortedDrawables.clear(); + impl->drawablesByTile.clear(); return count; }