Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] sort symbols using symbol-sort-key before placement (#16023)
Browse files Browse the repository at this point in the history
fix #15964
partially port mapbox/mapbox-gl-js#9054
  • Loading branch information
ansis authored and alexshalamov committed Feb 14, 2020
1 parent b7cc4f1 commit 761ef9c
Show file tree
Hide file tree
Showing 11 changed files with 242 additions and 31 deletions.
7 changes: 7 additions & 0 deletions src/mbgl/layout/symbol_instance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,11 @@ class SymbolInstance {
uint32_t crossTileID = 0;
};

class SortKeyRange {
public:
float sortKey;
size_t symbolInstanceStart;
size_t symbolInstanceEnd;
};

} // namespace mbgl
23 changes: 20 additions & 3 deletions src/mbgl/layout/symbol_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,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>());
Expand Down Expand Up @@ -560,6 +560,14 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
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()});
}
}
}
};

Expand Down Expand Up @@ -679,8 +687,17 @@ std::vector<float> CalculateTileDistances(const GeometryCoordinates& line, const
}

void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>& renderData, const bool firstLoad, const bool showCollisionBoxes) {
auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, iconsNeedLinear,
sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio,
auto bucket = std::make_shared<SymbolBucket>(layout,
layerPaintProperties,
textSize,
iconSize,
zoom,
iconsNeedLinear,
sortFeaturesByY,
bucketLeaderID,
std::move(symbolInstances),
std::move(sortKeyRanges),
tilePixelRatio,
allowVerticalPlacement,
std::move(placementModes));

Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/layout/symbol_layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class SymbolLayout final : public Layout {

const std::string bucketLeaderID;
std::vector<SymbolInstance> symbolInstances;
std::vector<SortKeyRange> sortKeyRanges;

static constexpr float INVALID_OFFSET_VALUE = std::numeric_limits<float>::max();
/**
Expand Down Expand Up @@ -105,6 +106,7 @@ class SymbolLayout final : public Layout {

bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
bool sortFeaturesByKey = false;
bool allowVerticalPlacement = false;
std::vector<style::TextWritingModeType> placementModes;

Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/renderer/buckets/symbol_bucket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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_)
Expand All @@ -36,6 +37,7 @@ SymbolBucket::SymbolBucket(Immutable<style::SymbolLayoutProperties::PossiblyEval
justReloaded(false),
hasVariablePlacement(false),
symbolInstances(symbolInstances_),
sortKeyRanges(sortKeyRanges_),
textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())),
iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())),
tilePixelRatio(tilePixelRatio_),
Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/renderer/buckets/symbol_bucket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class SymbolBucket final : public Bucket {
bool sortFeaturesByY,
const std::string bucketLeaderID,
const std::vector<SymbolInstance>&&,
const std::vector<SortKeyRange>&&,
const float tilePixelRatio,
bool allowVerticalPlacement,
std::vector<style::TextWritingModeType> placementModes);
Expand Down Expand Up @@ -100,6 +101,7 @@ class SymbolBucket final : public Bucket {
bool hasVariablePlacement : 1;

std::vector<SymbolInstance> symbolInstances;
std::vector<SortKeyRange> sortKeyRanges;

struct PaintProperties {
SymbolIconProgram::Binders iconBinders;
Expand Down
25 changes: 24 additions & 1 deletion src/mbgl/renderer/layers/render_symbol_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,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);
Expand Down Expand Up @@ -518,7 +520,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;
}
}
}
}
}
Expand Down
16 changes: 11 additions & 5 deletions src/mbgl/renderer/render_layer.hpp
Original file line number Diff line number Diff line change
@@ -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>

Expand All @@ -20,6 +20,7 @@ class RenderTile;
class TransformState;
class PatternAtlas;
class LineAtlas;
class SymbolBucket;

class LayerRenderData {
public:
Expand All @@ -29,9 +30,16 @@ class LayerRenderData {

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 {
Expand Down Expand Up @@ -95,9 +103,7 @@ class RenderLayer {

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;
Expand Down Expand Up @@ -126,7 +132,7 @@ class RenderLayer {
// 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
Expand Down
29 changes: 18 additions & 11 deletions src/mbgl/text/placement.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <list>
#include <mbgl/text/placement.hpp>

#include <mbgl/layout/symbol_layout.hpp>
Expand Down Expand Up @@ -110,12 +111,14 @@ void Placement::placeLayer(const RenderLayer& layer, const mat4& projMatrix, boo
std::set<uint32_t> seenCrossTileIDs;
for (const auto& item : layer.getPlacementData()) {
Bucket& bucket = item.bucket;
BucketPlacementParameters params{
item.tile,
projMatrix,
layer.baseImpl->source,
item.featureIndex,
showCollisionBoxes};
BucketPlacementParameters params{item.tile,
projMatrix,
layer.baseImpl->source,
item.featureIndex,
item.sortKey,
item.symbolInstanceStart,
item.symbolInstanceEnd,
showCollisionBoxes};
bucket.place(*this, params, seenCrossTileIDs);
}
}
Expand Down Expand Up @@ -518,13 +521,15 @@ void Placement::placeBucket(
placeSymbol(*it);
}
} 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,
Expand Down Expand Up @@ -590,7 +595,9 @@ void Placement::commit(TimePoint now, const double zoom) {
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);
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/mbgl/text/placement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ class BucketPlacementParameters {
const mat4& projMatrix;
std::string sourceId;
std::shared_ptr<FeatureIndex> featureIndex;
float sortKey;
size_t symbolInstanceStart;
size_t symbolInstanceEnd;
bool showCollisionBoxes;
};

Expand Down
15 changes: 14 additions & 1 deletion test/gl/bucket.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,22 @@ TEST(Buckets, SymbolBucket) {
bool sortFeaturesByY = false;
std::string bucketLeaderID = "test";
std::vector<SymbolInstance> symbolInstances;
std::vector<SortKeyRange> symbolRanges;

gl::Context context{ backend };
SymbolBucket bucket { std::move(layout), {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), 1.0f, false, {}};
SymbolBucket bucket{std::move(layout),
{},
16.0f,
1.0f,
0,
iconsNeedLinear,
sortFeaturesByY,
bucketLeaderID,
std::move(symbolInstances),
std::move(symbolRanges),
1.0f,
false,
{}};
ASSERT_FALSE(bucket.hasIconData());
ASSERT_FALSE(bucket.hasSdfIconData());
ASSERT_FALSE(bucket.hasTextData());
Expand Down
Loading

0 comments on commit 761ef9c

Please sign in to comment.