diff options
author | Ansis Brammanis <ansis@mapbox.com> | 2020-02-11 11:24:14 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-11 11:24:14 -0500 |
commit | 4f18d5fa92df175ac30f856a9273a00349b56cc3 (patch) | |
tree | 52efcbe12eb4f40890d6dcdc390036613b233519 /src/mbgl | |
parent | 98f99e07433d057880dcd30f21bcb4f1e147482d (diff) | |
download | qtlocation-mapboxgl-4f18d5fa92df175ac30f856a9273a00349b56cc3.tar.gz |
[core] sort symbols using symbol-sort-key before placement (#16023)
fix #15964
partially port mapbox/mapbox-gl-js#9054
Diffstat (limited to 'src/mbgl')
-rw-r--r-- | src/mbgl/layout/symbol_instance.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_layout.cpp | 45 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_layout.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_symbol_layer.cpp | 25 | ||||
-rw-r--r-- | src/mbgl/renderer/render_layer.hpp | 16 | ||||
-rw-r--r-- | src/mbgl/text/placement.cpp | 29 | ||||
-rw-r--r-- | src/mbgl/text/placement.hpp | 3 |
9 files changed, 105 insertions, 26 deletions
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 3cd67125b4..3303e5f7e3 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -123,4 +123,11 @@ public: static constexpr uint32_t invalidCrossTileID() { return std::numeric_limits<uint32_t>::max(); } }; +class SortKeyRange { +public: + float sortKey; + size_t symbolInstanceStart; + size_t symbolInstanceEnd; +}; + } // namespace mbgl diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index e0475f0acb..61c3b4ad66 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -106,7 +106,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, const bool hasSymbolSortKey = !leader.layout.get<SymbolSortKey>().isUndefined(); const auto symbolZOrder = layout->get<SymbolZOrder>(); - const bool sortFeaturesByKey = symbolZOrder != SymbolZOrderType::ViewportY && hasSymbolSortKey; + sortFeaturesByKey = symbolZOrder != SymbolZOrderType::ViewportY && hasSymbolSortKey; const bool zOrderByViewportY = symbolZOrder == SymbolZOrderType::ViewportY || (symbolZOrder == SymbolZOrderType::Auto && !sortFeaturesByKey); sortFeaturesByY = zOrderByViewportY && (layout->get<TextAllowOverlap>() || layout->get<IconAllowOverlap>() || layout->get<TextIgnorePlacement>() || layout->get<IconIgnorePlacement>()); @@ -572,9 +572,10 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, } } - auto addSymbolInstance = [&] (Anchor& anchor, std::shared_ptr<SymbolInstanceSharedData> sharedData) { + auto addSymbolInstance = [&](Anchor& anchor, std::shared_ptr<SymbolInstanceSharedData> sharedData) { assert(sharedData); - const bool anchorInsideTile = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT; + const bool anchorInsideTile = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && + anchor.point.y < util::EXTENT; if (mode == MapMode::Tile || anchorInsideTile) { // For static/continuous rendering, only add symbols anchored within this tile: @@ -582,13 +583,36 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, // In tiled rendering mode, add all symbols in the buffers so that we can: // (1) render symbols that overlap into this tile // (2) approximate collision detection effects from neighboring symbols - symbolInstances.emplace_back(anchor, std::move(sharedData), shapedTextOrientations, - shapedIcon, verticallyShapedIcon, - textBoxScale, textPadding, textPlacement, textOffset, - iconBoxScale, iconPadding, iconOffset, indexedFeature, - layoutFeatureIndex, feature.index, - feature.formattedText ? feature.formattedText->rawText() : std::u16string(), - overscaling, iconRotation, textRotation, variableTextOffset, allowVerticalPlacement, iconType); + symbolInstances.emplace_back(anchor, + std::move(sharedData), + shapedTextOrientations, + shapedIcon, + verticallyShapedIcon, + textBoxScale, + textPadding, + textPlacement, + textOffset, + iconBoxScale, + iconPadding, + iconOffset, + indexedFeature, + layoutFeatureIndex, + feature.index, + feature.formattedText ? feature.formattedText->rawText() : std::u16string(), + overscaling, + iconRotation, + textRotation, + variableTextOffset, + allowVerticalPlacement, + iconType); + + if (sortFeaturesByKey) { + if (sortKeyRanges.size() && sortKeyRanges.back().sortKey == feature.sortKey) { + sortKeyRanges.back().symbolInstanceEnd = symbolInstances.size(); + } else { + sortKeyRanges.push_back({feature.sortKey, symbolInstances.size() - 1, symbolInstances.size()}); + } + } } }; @@ -728,6 +752,7 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), + std::move(sortKeyRanges), tilePixelRatio, allowVerticalPlacement, std::move(placementModes), diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index b906b0b36c..52c912c8ae 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -45,6 +45,7 @@ public: const std::string bucketLeaderID; std::vector<SymbolInstance> symbolInstances; + std::vector<SortKeyRange> sortKeyRanges; static constexpr float INVALID_OFFSET_VALUE = std::numeric_limits<float>::max(); /** @@ -115,6 +116,7 @@ private: bool iconsNeedLinear = false; bool sortFeaturesByY = false; + bool sortFeaturesByKey = false; bool allowVerticalPlacement = false; bool iconsInText = false; std::vector<style::TextWritingModeType> placementModes; diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 55002e7851..7b8eec4471 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -23,6 +23,7 @@ SymbolBucket::SymbolBucket(Immutable<style::SymbolLayoutProperties::PossiblyEval bool sortFeaturesByY_, const std::string bucketName_, const std::vector<SymbolInstance>&& symbolInstances_, + const std::vector<SortKeyRange>&& sortKeyRanges_, float tilePixelRatio_, bool allowVerticalPlacement_, std::vector<style::TextWritingModeType> placementModes_, @@ -40,6 +41,7 @@ SymbolBucket::SymbolBucket(Immutable<style::SymbolLayoutProperties::PossiblyEval hasVariablePlacement(false), hasUninitializedSymbols(false), symbolInstances(symbolInstances_), + sortKeyRanges(sortKeyRanges_), textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())), iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())), tilePixelRatio(tilePixelRatio_), diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 82d8c682aa..2b41ac9295 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -73,6 +73,7 @@ public: bool sortFeaturesByY, const std::string bucketLeaderID, const std::vector<SymbolInstance>&&, + const std::vector<SortKeyRange>&&, const float tilePixelRatio, bool allowVerticalPlacement, std::vector<style::TextWritingModeType> placementModes, @@ -117,6 +118,7 @@ public: bool hasUninitializedSymbols : 1; std::vector<SymbolInstance> symbolInstances; + std::vector<SortKeyRange> sortKeyRanges; struct PaintProperties { SymbolIconProgram::Binders iconBinders; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 17376fd864..955ad2ce51 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -424,6 +424,8 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end()); const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); + bucket.justReloaded = false; + auto addRenderables = [&renderableSegments, &tile, renderData, &bucketPaintProperties, it = renderableSegments.begin()] (auto& segments, const SymbolType type) mutable { for (auto& segment : segments) { it = renderableSegments.emplace_hint(it, SegmentWrapper{std::ref(segment)}, tile, *renderData, bucketPaintProperties, segment.sortKey, type); @@ -580,7 +582,28 @@ void RenderSymbolLayer::prepare(const LayerPrepareParameters& params) { const Tile* tile = params.source->getRenderedTile(renderTile.id); assert(tile); assert(tile->kind == Tile::Kind::Geometry); - placementData.push_back({*bucket, renderTile, static_cast<const GeometryTile*>(tile)->getFeatureIndex()}); + + bool firstInBucket = true; + auto featureIndex = static_cast<const GeometryTile*>(tile)->getFeatureIndex(); + + if (bucket->sortKeyRanges.empty()) { + placementData.push_back( + {*bucket, renderTile, featureIndex, firstInBucket, 0.0f, 0, bucket->symbolInstances.size()}); + } else { + for (const SortKeyRange& sortKeyRange : bucket->sortKeyRanges) { + LayerPlacementData layerData{*bucket, + renderTile, + featureIndex, + firstInBucket, + sortKeyRange.sortKey, + sortKeyRange.symbolInstanceStart, + sortKeyRange.symbolInstanceEnd}; + auto sortPosition = std::upper_bound(placementData.cbegin(), placementData.cend(), layerData); + placementData.insert(sortPosition, std::move(layerData)); + + firstInBucket = false; + } + } } } } diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index ba3c638f88..4931893271 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -1,11 +1,11 @@ #pragma once +#include <list> #include <mbgl/layout/layout.hpp> #include <mbgl/renderer/render_pass.hpp> #include <mbgl/renderer/render_source.hpp> #include <mbgl/style/layer_properties.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/util/mat4.hpp> - #include <memory> #include <string> @@ -20,6 +20,7 @@ class RenderTile; class TransformState; class PatternAtlas; class LineAtlas; +class SymbolBucket; class LayerRenderData { public: @@ -29,9 +30,16 @@ public: class LayerPlacementData { public: + friend bool operator<(const LayerPlacementData& lhs, const LayerPlacementData& rhs) { + return lhs.sortKey < rhs.sortKey; + } std::reference_wrapper<Bucket> bucket; std::reference_wrapper<const RenderTile> tile; std::shared_ptr<FeatureIndex> featureIndex; + bool firstInBucket; + float sortKey; + size_t symbolInstanceStart; + size_t symbolInstanceEnd; }; class LayerPrepareParameters { @@ -95,9 +103,7 @@ public: virtual void prepare(const LayerPrepareParameters&); - const std::vector<LayerPlacementData>& getPlacementData() const { - return placementData; - } + const std::list<LayerPlacementData>& getPlacementData() const { return placementData; } // Latest evaluated properties. Immutable<style::LayerProperties> evaluatedProperties; @@ -126,7 +132,7 @@ protected: // evaluated StyleProperties object and is updated accordingly. RenderPass passes = RenderPass::None; - std::vector<LayerPlacementData> placementData; + std::list<LayerPlacementData> placementData; private: // Some layers may not render correctly on some hardware when the vertex attribute limit of diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index c927fdd782..57cf1f0f1f 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -1,11 +1,11 @@ -#include <mbgl/text/placement.hpp> - +#include <list> #include <mbgl/layout/symbol_layout.hpp> #include <mbgl/renderer/bucket.hpp> #include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/renderer/render_layer.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/update_parameters.hpp> +#include <mbgl/text/placement.hpp> #include <mbgl/tile/geometry_tile.hpp> #include <mbgl/util/math.hpp> #include <utility> @@ -113,7 +113,12 @@ void Placement::placeLayer(const RenderLayer& layer) { std::set<uint32_t> seenCrossTileIDs; for (const auto& item : layer.getPlacementData()) { Bucket& bucket = item.bucket; - BucketPlacementParameters params{item.tile, layer.baseImpl->source, item.featureIndex}; + BucketPlacementParameters params{item.tile, + layer.baseImpl->source, + item.featureIndex, + item.sortKey, + item.symbolInstanceStart, + item.symbolInstanceEnd}; bucket.place(*this, params, seenCrossTileIDs); } } @@ -656,18 +661,20 @@ void Placement::placeBucket(const SymbolBucket& bucket, } } else { - for (const SymbolInstance& symbol : bucket.symbolInstances) { - placeSymbol(symbol); + auto beginIt = bucket.symbolInstances.begin() + params.symbolInstanceStart; + auto endIt = bucket.symbolInstances.begin() + params.symbolInstanceEnd; + assert(params.symbolInstanceStart < params.symbolInstanceEnd); + assert(params.symbolInstanceEnd <= bucket.symbolInstances.size()); + for (auto it = beginIt; it != endIt; ++it) { + placeSymbol(*it); } } - bucket.justReloaded = false; - // As long as this placement lives, we have to hold onto this bucket's // matching FeatureIndex/data for querying purposes retainedQueryData.emplace(std::piecewise_construct, - std::forward_as_tuple(bucket.bucketInstanceId), - std::forward_as_tuple(bucket.bucketInstanceId, params.featureIndex, overscaledID)); + std::forward_as_tuple(bucket.bucketInstanceId), + std::forward_as_tuple(bucket.bucketInstanceId, params.featureIndex, overscaledID)); } void Placement::commit() { @@ -737,7 +744,9 @@ void Placement::commit() { void Placement::updateLayerBuckets(const RenderLayer& layer, const TransformState& state, bool updateOpacities) const { std::set<uint32_t> seenCrossTileIDs; for (const auto& item : layer.getPlacementData()) { - item.bucket.get().updateVertices(*this, updateOpacities, state, item.tile, seenCrossTileIDs); + if (item.firstInBucket) { + item.bucket.get().updateVertices(*this, updateOpacities, state, item.tile, seenCrossTileIDs); + } } } diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index 46d560b673..9fbd6b9743 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -91,6 +91,9 @@ public: const RenderTile& tile; std::string sourceId; std::shared_ptr<FeatureIndex> featureIndex; + float sortKey; + size_t symbolInstanceStart; + size_t symbolInstanceEnd; }; class Placement; |