From b9b29e16d7ee161ada3007a95aa32b7896542107 Mon Sep 17 00:00:00 2001 From: Tim Sylvester Date: Fri, 2 Aug 2024 11:49:57 -0700 Subject: [PATCH] add support for `reference_wrapper` integrate with `render_layer` start on fill conversion --- .../renderer/layers/render_fill_layer.cpp | 66 +++++++++++++++++-- src/mbgl/renderer/render_layer.cpp | 23 +++++++ src/mbgl/renderer/render_layer.hpp | 3 + src/mbgl/renderer/render_source.hpp | 3 + .../renderer/sources/render_tile_source.cpp | 16 ++++- .../renderer/sources/render_tile_source.hpp | 7 +- src/mbgl/tile/tile_diff.hpp | 55 ++++++++++------ 7 files changed, 146 insertions(+), 27 deletions(-) diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 63f9ecfec52..aafba7400f5 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -357,15 +358,70 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, builder.setEnableStencil(true); }; - stats.drawablesRemoved += fillTileLayerGroup->removeDrawablesIf([&](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(); - return tileID && !hasRenderTile(*tileID); - }); + // Remove drawables for removed tiles + for (const auto& tileID : renderTileDiff->removed) { + removeTile(renderPass, tileID); + } fillTileLayerGroup->setStencilTiles(renderTiles); StringIDSetsPair propertiesAsUniforms; + + // Update tiles that weren't added or removed + std::vector resetTileIDs; + for (const auto& tileID : renderTileDiff->remainder) { + const auto tileRef = getRenderTile(tileID); + if (!tileRef) { + assert(false); + continue; + } + const RenderTile& tile = tileRef->get(); + + const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass); + if (!renderData || !renderData->bucket || !renderData->bucket->hasData()) { + removeTile(renderPass, tileID); + + if (renderData && !renderData->bucket) { + // We'll need to treat this tile as an add + resetTileIDs.push_back(tileID); + } + continue; + } + + auto& bucket = static_cast(*renderData->bucket); + + const auto prevBucketID = getRenderTileBucketID(tileID); + if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) { + // This tile was previously set up from a different bucket, drop and re-create any drawables for it. + removeTile(renderPass, tileID); + + // We'll need to treat this tile as an add + resetTileIDs.push_back(tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + } + + // Create drawables for new tiles + const auto newTile = [&](const OverscaledTileID& tileID) { + const auto tileRef = getRenderTile(tileID); + if (!tileRef) { + assert(false); + return; + } + const RenderTile& tile = tileRef->get(); + + const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass); + if (!renderData || !renderData->bucket || !renderData->bucket->hasData()) { + return; + } + + auto& bucket = static_cast(*renderData->bucket); + setRenderTileBucketID(tileID, bucket.getID()); + }; + // With C++20 we can chain iterator ranges and use `for(:)` + std::for_each(renderTileDiff->added.begin(), renderTileDiff->added.end(), newTile); + std::for_each(resetTileIDs.begin(), resetTileIDs.end(), newTile); + for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 5a52417694f..6dc348f8a29 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #if MLN_DRAWABLE_RENDERER @@ -58,6 +60,7 @@ void RenderLayer::prepare(const LayerPrepareParameters& params) { assert(params.source); assert(params.source->isEnabled()); renderTiles = params.source->getRenderTiles(); + renderTileDiff = params.source->getRenderTileDiff(); addRenderPassesFromTiles(); #if MLN_DRAWABLE_RENDERER @@ -140,6 +143,24 @@ const LayerRenderData* RenderLayer::getRenderDataForPass(const RenderTile& tile, return nullptr; } +std::optional> RenderLayer::getRenderTile( + const OverscaledTileID& tileID) const { + // Search `RenderTiles` for a tile ID without creating a "key" instance of `RenderTile` + struct Comp { + bool operator()(const std::reference_wrapper& tile, const OverscaledTileID& id) const { + return tile.get().getOverscaledTileID() < id; + } + bool operator()(const OverscaledTileID& id, const std::reference_wrapper& tile) const { + return id < tile.get().getOverscaledTileID(); + } + }; + const auto result = std::lower_bound(renderTiles->begin(), renderTiles->end(), tileID, Comp()); + if (result != renderTiles->end() && result->get().getOverscaledTileID() == tileID) { + return *result; + } + return std::nullopt; +} + #if MLN_DRAWABLE_RENDERER std::size_t RenderLayer::removeTile(RenderPass renderPass, const OverscaledTileID& tileID) { if (const auto tileGroup = static_cast(layerGroup.get())) { @@ -161,6 +182,8 @@ std::size_t RenderLayer::removeAllDrawables() { } void RenderLayer::updateRenderTileIDs() { + MLN_TRACE_FUNC() + if (!renderTiles || renderTiles->empty()) { renderTileIDs.clear(); return; diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index 81cf911be89..2e0d0644a90 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -205,6 +205,8 @@ class RenderLayer { const LayerRenderData* getRenderDataForPass(const RenderTile&, RenderPass) const; + std::optional> getRenderTile(const OverscaledTileID& tileID) const; + #if MLN_DRAWABLE_RENDERER void setLayerGroup(LayerGroupBasePtr, UniqueChangeRequestVec&); @@ -275,6 +277,7 @@ class RenderLayer { protected: // Stores current set of tiles to be rendered for this layer. RenderTiles renderTiles; + std::shared_ptr renderTileDiff; // Stores what render passes this layer is currently enabled for. This depends on the // evaluated StyleProperties object and is updated accordingly. diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index f9925d49182..7816de966a9 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -30,6 +30,7 @@ class RenderTile; class Scheduler; class SourceQueryOptions; class Tile; +class TileDifference; class TileParameters; class TransformParameters; class TransformState; @@ -69,6 +70,8 @@ class RenderSource : protected TileObserver { // If supported, returns a shared list of RenderTiles, sorted by tile id and // excluding tiles hold for fade; returns nullptr otherwise. virtual RenderTiles getRenderTiles() const { return nullptr; } + // If supported, returns a description of the tile IDs which were added and removed in the last `prepare` + virtual std::shared_ptr getRenderTileDiff() const { return nullptr; } // If supported, returns a shared list of RenderTiles, sorted in opposite y // position, so tiles with overlapping symbols are drawn on top of each other, // with lower symbols being drawn on top of higher symbols; returns nullptr otherwise. diff --git a/src/mbgl/renderer/sources/render_tile_source.cpp b/src/mbgl/renderer/sources/render_tile_source.cpp index 30c02d92616..13b40742288 100644 --- a/src/mbgl/renderer/sources/render_tile_source.cpp +++ b/src/mbgl/renderer/sources/render_tile_source.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -387,7 +388,8 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr RenderTileSource::RenderTileSource(Immutable impl_, const TaggedScheduler& threadPool_) : RenderSource(std::move(impl_)), tilePyramid(threadPool_), - renderTiles(makeMutable>()) { + renderTiles(makeMutable>()), + previousRenderTiles(makeMutable>()) { tilePyramid.setObserver(this); } @@ -414,6 +416,9 @@ void RenderTileSource::prepare(const SourcePrepareParameters& parameters) { tiles->back().prepare(parameters); } featureState.coalesceChanges(*tiles); + + renderTileDiff.reset(); + previousRenderTiles = std::move(renderTiles); renderTiles = std::move(tiles); } @@ -439,6 +444,15 @@ RenderTiles RenderTileSource::getRenderTiles() const { return filteredRenderTiles; } +std::shared_ptr RenderTileSource::getRenderTileDiff() const { + if (!renderTileDiff) { + const auto tiles = getRenderTiles(); + renderTileDiff = std::make_shared( + diffTiles(previousRenderTiles->begin(), previousRenderTiles->end(), tiles->begin(), tiles->end())); + } + return renderTileDiff; +} + RenderTiles RenderTileSource::getRenderTilesSortedByYPosition() const { if (!renderTilesSortedByY) { const auto comp = [sourceBearing = this->bearing](const RenderTile& a, const RenderTile& b) { diff --git a/src/mbgl/renderer/sources/render_tile_source.hpp b/src/mbgl/renderer/sources/render_tile_source.hpp index 5ad78e11c08..b6065da0134 100644 --- a/src/mbgl/renderer/sources/render_tile_source.hpp +++ b/src/mbgl/renderer/sources/render_tile_source.hpp @@ -1,10 +1,10 @@ #pragma once #include +#include #include #include #include -#include #if MLN_DRAWABLE_RENDERER #include @@ -12,6 +12,8 @@ namespace mbgl { +class TileDifference; + /** * @brief Base class for render sources that provide render tiles. */ @@ -27,6 +29,7 @@ class RenderTileSource : public RenderSource { bool hasFadingTiles() const override; RenderTiles getRenderTiles() const override; + std::shared_ptr getRenderTileDiff() const override; RenderTiles getRenderTilesSortedByYPosition() const override; const Tile* getRenderedTile(const UnwrappedTileID&) const override; @@ -55,6 +58,8 @@ class RenderTileSource : public RenderSource { RenderTileSource(Immutable, const TaggedScheduler&); TilePyramid tilePyramid; Immutable> renderTiles; + Immutable> previousRenderTiles; + mutable std::shared_ptr renderTileDiff; mutable RenderTiles filteredRenderTiles; mutable RenderTiles renderTilesSortedByY; diff --git a/src/mbgl/tile/tile_diff.hpp b/src/mbgl/tile/tile_diff.hpp index 05ebd8339f7..f2fc556c334 100644 --- a/src/mbgl/tile/tile_diff.hpp +++ b/src/mbgl/tile/tile_diff.hpp @@ -12,31 +12,38 @@ namespace mbgl { class RenderTile; -class TileDifference { -public: - std::vector added; - std::vector removed; - std::vector remainder; +struct TileDifference { + const std::vector added; + const std::vector removed; + const std::vector remainder; }; -namespace detail { -// Iterate a collection of `RenderTile` as if they were tile IDs +namespace tile_diff_detail { + +template +inline constexpr bool is_ref_wrap = std::is_same_v, std::reference_wrapper>; +template +using adaptor_base = boost::iterator_adaptor; + +// Iterate a collection of `RenderTile` (or `reference_wrapper` thereto) as if they were tile IDs +template || is_ref_wrap> +struct TileIDIterator : public adaptor_base> { + const OverscaledTileID& dereference() const { return this->base()->get().getOverscaledTileID(); } + TileIDIterator(const TileIDIterator::iterator_adaptor_::base_type& p) + : TileIDIterator::iterator_adaptor_(p) {} +}; template -struct TileIDIterator : public boost::iterator_adaptor, - T, - UnwrappedTileID, - boost::random_access_traversal_tag, - const UnwrappedTileID&> { - const UnwrappedTileID& dereference() const { return this->base()->id; } +struct TileIDIterator : public adaptor_base> { + const OverscaledTileID& dereference() const { return this->base()->getOverscaledTileID(); } TileIDIterator(const TileIDIterator::iterator_adaptor_::base_type& p) : TileIDIterator::iterator_adaptor_(p) {} }; -} // namespace detail +} // namespace tile_diff_detail /// @brief Compute the differences in tile IDs between two containers of `RenderTile` ordered by tile ID template TileDifference diffTiles(TIterA aBeg_, TIterA aEnd_, TIterB bBeg_, TIterB bEnd_) { - using namespace detail; + using namespace tile_diff_detail; const TileIDIterator aBeg = aBeg_; const TileIDIterator aEnd = aEnd_; const TileIDIterator bBeg = bBeg_; @@ -45,12 +52,20 @@ TileDifference diffTiles(TIterA aBeg_, TIterA aEnd_, TIterB bBeg_, TIterB bEnd_) assert(std::is_sorted(aBeg, aEnd)); assert(std::is_sorted(bBeg, bEnd)); - TileDifference result; - std::set_difference(aBeg, aEnd, bBeg, bEnd, std::back_inserter(result.removed)); - std::set_difference(bBeg, bEnd, aBeg, aEnd, std::back_inserter(result.added)); - std::set_intersection(aBeg, aEnd, bBeg, bEnd, std::back_inserter(result.remainder)); + std::vector added; + std::set_difference(bBeg, bEnd, aBeg, aEnd, std::back_inserter(added)); + + std::vector removed; + std::set_difference(aBeg, aEnd, bBeg, bEnd, std::back_inserter(removed)); + + std::vector remainder; + std::set_intersection(aBeg, aEnd, bBeg, bEnd, std::back_inserter(remainder)); - return result; + return { + std::move(added), + std::move(removed), + std::move(remainder), + }; } } // namespace mbgl