diff options
author | Mikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com> | 2019-05-22 16:41:40 +0300 |
---|---|---|
committer | Mikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com> | 2019-05-24 10:54:06 +0300 |
commit | aa3a7cf02f2b5d0b99bec9d335c9681dcfa38426 (patch) | |
tree | 08d9826c1b419960a1e7a03b6fefb6d21aeab923 | |
parent | d8e9acd0f510a811f5c1fa87738be646ff83b715 (diff) | |
download | qtlocation-mapboxgl-aa3a7cf02f2b5d0b99bec9d335c9681dcfa38426.tar.gz |
[core] SymbolBucket updates complete at placement stage
`RenderSymbolLayer` does not have to update dynamic vertices of its buckets, this logic is moved to placement (which is already updates opacity vertices).
* fixes clustering of labels when text variable placement enabled - as assignes `usesVariablePlacement` per bucket
* simplifies the code in `RenderSymbolLayer` (the `RenderSymbolLayer::upload()` is now omitted).
* symbol buckets are not modified after orchestration finishes
-rw-r--r-- | src/mbgl/layout/symbol_projection.cpp | 12 | ||||
-rw-r--r-- | src/mbgl/layout/symbol_projection.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/bucket.hpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.cpp | 33 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_symbol_layer.cpp | 157 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_symbol_layer.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/renderer_impl.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/renderer/upload_parameters.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/text/placement.cpp | 105 | ||||
-rw-r--r-- | src/mbgl/text/placement.hpp | 6 |
11 files changed, 143 insertions, 194 deletions
diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp index b7858f8deb..a58d90d4cf 100644 --- a/src/mbgl/layout/symbol_projection.cpp +++ b/src/mbgl/layout/symbol_projection.cpp @@ -361,15 +361,13 @@ namespace mbgl { void reprojectLineLabels(gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertexArray, const std::vector<PlacedSymbol>& placedSymbols, - const mat4& posMatrix, const style::SymbolPropertyValues& values, + const mat4& posMatrix, bool pitchWithMap, bool rotateWithMap, bool keepUpright, const RenderTile& tile, const SymbolSizeBinder& sizeBinder, const TransformState& state) { const ZoomEvaluatedSize partiallyEvaluatedSize = sizeBinder.evaluateForZoom(state.getZoom()); const std::array<double, 2> clippingBuffer = {{ 256.0 / state.getSize().width * 2.0 + 1.0, 256.0 / state.getSize().height * 2.0 + 1.0 }}; - - const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map; - const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map; + const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1, state.getZoom()); const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, pitchWithMap, @@ -405,19 +403,19 @@ namespace mbgl { const float perspectiveRatio = 0.5 + 0.5 * (cameraToAnchorDistance / state.getCameraToCenterDistance()); const float fontSize = evaluateSizeForFeature(partiallyEvaluatedSize, placedSymbol); - const float pitchScaledFontSize = values.pitchAlignment == style::AlignmentType::Map ? + const float pitchScaledFontSize = pitchWithMap ? fontSize * perspectiveRatio : fontSize / perspectiveRatio; const Point<float> anchorPoint = project(placedSymbol.anchorPoint, labelPlaneMatrix).first; - PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio()); + PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio()); useVertical = placeUnflipped == PlacementResult::UseVertical; if (placeUnflipped == PlacementResult::NotEnoughRoom || useVertical || (placeUnflipped == PlacementResult::NeedsFlipping && - placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio()) == PlacementResult::NotEnoughRoom)) { + placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio()) == PlacementResult::NotEnoughRoom)) { hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray); } } diff --git a/src/mbgl/layout/symbol_projection.hpp b/src/mbgl/layout/symbol_projection.hpp index 3699eee290..58c635eaae 100644 --- a/src/mbgl/layout/symbol_projection.hpp +++ b/src/mbgl/layout/symbol_projection.hpp @@ -47,7 +47,7 @@ namespace mbgl { PointAndCameraDistance project(const Point<float>& point, const mat4& matrix); void reprojectLineLabels(gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>&, const std::vector<PlacedSymbol>&, - const mat4& posMatrix, const style::SymbolPropertyValues&, + const mat4& posMatrix, bool pitchWithMap, bool rotateWithMap, bool keepUpright, const RenderTile&, const SymbolSizeBinder& sizeBinder, const TransformState&); optional<std::pair<PlacedGlyph, PlacedGlyph>> placeFirstAndLastGlyph(const float fontScale, diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index c02e2ec341..665fc1bfa5 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -19,6 +19,7 @@ class PatternDependency; using PatternLayerMap = std::map<std::string, PatternDependency>; class Placement; class BucketPlacementParameters; +class RenderTile; class Bucket { public: @@ -59,7 +60,7 @@ public: } // Places this bucket to the given placement. Returns bucket cross-tile id on success call; `0` otherwise. virtual uint32_t place(Placement&, const BucketPlacementParameters&, std::set<uint32_t>&) { return 0u; } - virtual void updateOpacities(Placement&, std::set<uint32_t>&) {} + virtual void updateVertices(Placement&, bool /*updateOpacities*/, const RenderTile&, std::set<uint32_t>&) {} protected: Bucket() = default; diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 381ef5b24b..06fccb8ffd 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -10,7 +10,7 @@ namespace mbgl { using namespace style; namespace { - std::atomic<uint32_t> maxBucketInstanceId; +std::atomic<uint32_t> maxBucketInstanceId; } // namespace SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layout_, @@ -62,7 +62,11 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) { } if (!dynamicUploaded) { - text.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(text.dynamicVertices), gfx::BufferUsageType::StreamDraw); + if (!text.dynamicVertexBuffer) { + text.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(text.dynamicVertices), gfx::BufferUsageType::StreamDraw); + } else { + uploadPass.updateVertexBuffer(*text.dynamicVertexBuffer, std::move(text.dynamicVertices)); + } } if (!placementChangesUploaded) { if (!text.opacityVertexBuffer) { @@ -84,7 +88,11 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) { uploadPass.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles)); } if (!dynamicUploaded) { - icon.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.dynamicVertices), gfx::BufferUsageType::StreamDraw); + if (!icon.dynamicVertexBuffer) { + icon.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.dynamicVertices), gfx::BufferUsageType::StreamDraw); + } else { + uploadPass.updateVertexBuffer(*icon.dynamicVertexBuffer, std::move(icon.dynamicVertices)); + } } if (!placementChangesUploaded) { if (!icon.opacityVertexBuffer) { @@ -150,11 +158,6 @@ bool SymbolBucket::hasCollisionCircleData() const { return !collisionCircle.segments.empty(); } -void SymbolBucket::updateOpacity() { - placementChangesUploaded = false; - uploaded = false; -} - void addPlacedSymbol(gfx::IndexVector<gfx::Triangles>& triangles, const PlacedSymbol& placedSymbol) { auto endIndex = placedSymbol.vertexStartIndex + placedSymbol.glyphOffsets.size() * 4; for (auto vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) { @@ -242,8 +245,8 @@ bool SymbolBucket::hasFormatSectionOverrides() const { } std::pair<uint32_t, bool> SymbolBucket::registerAtCrossTileIndex(CrossTileSymbolLayerIndex& index, const OverscaledTileID& tileID, uint32_t& maxCrossTileID) { - bool added = index.addBucket(tileID, *this, maxCrossTileID); - return std::make_pair(bucketInstanceId, added); + bool firstTimeAdded = index.addBucket(tileID, *this, maxCrossTileID); + return std::make_pair(bucketInstanceId, firstTimeAdded); } uint32_t SymbolBucket::place(Placement& placement, const BucketPlacementParameters& params, std::set<uint32_t>& seenIds) { @@ -251,8 +254,14 @@ uint32_t SymbolBucket::place(Placement& placement, const BucketPlacementParamete return bucketInstanceId; } -void SymbolBucket::updateOpacities(Placement& placement, std::set<uint32_t>& seenIds) { - placement.updateBucketOpacities(*this, seenIds); +void SymbolBucket::updateVertices(Placement& placement, bool updateOpacities, const RenderTile& tile, std::set<uint32_t>& seenIds) { + if (updateOpacities) { + placement.updateBucketOpacities(*this, seenIds); + placementChangesUploaded = false; + } + placement.updateBucketDynamicVertices(*this, tile); + dynamicUploaded = false; + uploaded = false; } } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 3b61002890..e47672f1cd 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -60,14 +60,14 @@ public: bool hasData() const override; std::pair<uint32_t, bool> registerAtCrossTileIndex(CrossTileSymbolLayerIndex&, const OverscaledTileID&, uint32_t& maxCrossTileID) override; uint32_t place(Placement&, const BucketPlacementParameters&, std::set<uint32_t>&) override; - void updateOpacities(Placement&, std::set<uint32_t>&) override; + void updateVertices(Placement&, bool updateOpacities, const RenderTile&, std::set<uint32_t>&) override; bool hasTextData() const; bool hasIconData() const; bool hasCollisionBoxData() const; bool hasCollisionCircleData() const; bool hasFormatSectionOverrides() const; - void updateOpacity(); + void sortFeatures(const float angle); // The result contains references to the `symbolInstances` items, sorted by viewport Y. std::vector<std::reference_wrapper<SymbolInstance>> getSortedSymbols(const float angle); @@ -138,6 +138,7 @@ public: const float tilePixelRatio; uint32_t bucketInstanceId; bool justReloaded = false; + bool hasVariablePlacement = false; mutable optional<bool> hasFormatSectionOverrides_; std::shared_ptr<std::vector<size_t>> featureSortOrder; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 7fc0e08b41..dc67dea7e3 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -15,9 +15,7 @@ #include <mbgl/tile/geometry_tile.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> -#include <mbgl/text/placement.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/layout/symbol_projection.hpp> #include <mbgl/layout/symbol_layout.hpp> #include <mbgl/layout/symbol_layout.hpp> #include <mbgl/util/math.hpp> @@ -29,16 +27,6 @@ namespace mbgl { using namespace style; namespace { -Point<float> calculateVariableRenderShift(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale, float renderTextSize) { - AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); - float shiftX = -(alignment.horizontalAlign - 0.5f) * width; - float shiftY = -(alignment.verticalAlign - 0.5f) * height; - Point<float> offset = SymbolLayout::evaluateRadialOffset(anchor, radialOffset); - return Point<float>( - (shiftX / textBoxScale + offset.x) * renderTextSize, - (shiftY / textBoxScale + offset.y) * renderTextSize - ); -} style::SymbolPropertyValues iconPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { @@ -116,122 +104,6 @@ struct RenderableSegment { } }; -void uploadIcon(gfx::UploadPass& uploadPass, - UploadParameters& uploadParameters, - const RenderTile& tile, - const LayerRenderData& renderData) { - assert(tile.tile.kind == Tile::Kind::Geometry); - auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket); - const auto& layout = bucket.layout; - - const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point && - layout.get<IconRotationAlignment>() == AlignmentType::Map; - - if (alongLine) { - const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties); - reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols, tile.matrix, - iconPropertyValues(evaluated, layout), tile, *bucket.iconSizeBinder, - uploadParameters.state); - - uploadPass.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, - std::move(bucket.icon.dynamicVertices)); - } -} - -void uploadText(gfx::UploadPass& uploadPass, - UploadParameters& uploadParameters, - const RenderTile& tile, - const LayerRenderData& renderData, - bool& hasVariablePlacement) { - assert(tile.tile.kind == Tile::Kind::Geometry); - auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket); - const auto& layout = bucket.layout; - - const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point && - layout.get<TextRotationAlignment>() == AlignmentType::Map; - - if (alongLine) { - const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties); - reprojectLineLabels(bucket.text.dynamicVertices, - bucket.text.placedSymbols, - tile.matrix, - textPropertyValues(evaluated, layout), - tile, - *bucket.textSizeBinder, - uploadParameters.state); - - uploadPass.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); - } else if (!layout.get<TextVariableAnchor>().empty()) { - bucket.text.dynamicVertices.clear(); - - hasVariablePlacement = false; - - const auto partiallyEvaluatedSize = bucket.textSizeBinder->evaluateForZoom(uploadParameters.state.getZoom()); - const float tileScale = std::pow(2, uploadParameters.state.getZoom() - tile.tile.id.overscaledZ); - const bool rotateWithMap = layout.get<TextRotationAlignment>() == AlignmentType::Map; - const bool pitchWithMap = layout.get<TextPitchAlignment>() == AlignmentType::Map; - const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, uploadParameters.state.getZoom()); - const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, uploadParameters.state, pixelsToTileUnits); - - for (const PlacedSymbol& symbol : bucket.text.placedSymbols) { - optional<VariableOffset> variableOffset; - if (!symbol.hidden && symbol.crossTileID != 0u) { - auto it = uploadParameters.variableOffsets.find(symbol.crossTileID); - if (it != uploadParameters.variableOffsets.end()) { - hasVariablePlacement |= true; - variableOffset = it->second; - } - } - - if (!variableOffset) { - // These symbols are from a justification that is not being used, or a label that wasn't placed - // so we don't need to do the extra math to figure out what incremental shift to apply. - hideGlyphs(symbol.glyphOffsets.size(), bucket.text.dynamicVertices); - } else { - const Point<float> tileAnchor = symbol.anchorPoint; - const auto projectedAnchor = project(tileAnchor, pitchWithMap ? tile.matrix : labelPlaneMatrix); - const float perspectiveRatio = 0.5f + 0.5f * (uploadParameters.state.getCameraToCenterDistance() / projectedAnchor.second); - float renderTextSize = evaluateSizeForFeature(partiallyEvaluatedSize, symbol) * perspectiveRatio / util::ONE_EM; - if (pitchWithMap) { - // Go from size in pixels to equivalent size in tile units - renderTextSize *= bucket.tilePixelRatio / tileScale; - } - - auto shift = calculateVariableRenderShift( - (*variableOffset).anchor, - (*variableOffset).width, - (*variableOffset).height, - (*variableOffset).radialOffset, - (*variableOffset).textBoxScale, - renderTextSize); - - // Usual case is that we take the projected anchor and add the pixel-based shift - // calculated above. In the (somewhat weird) case of pitch-aligned text, we add an equivalent - // tile-unit based shift to the anchor before projecting to the label plane. - Point<float> shiftedAnchor; - if (pitchWithMap) { - shiftedAnchor = project(Point<float>(tileAnchor.x + shift.x, tileAnchor.y + shift.y), - labelPlaneMatrix).first; - } else { - if (rotateWithMap) { - auto rotated = util::rotate(shift, -uploadParameters.state.getPitch()); - shiftedAnchor = Point<float>(projectedAnchor.first.x + rotated.x, - projectedAnchor.first.y + rotated.y); - } else { - shiftedAnchor = Point<float>(projectedAnchor.first.x + shift.x, - projectedAnchor.first.y + shift.y); - } - } - - for (std::size_t i = 0; i < symbol.glyphOffsets.size(); i++) { - addDynamicAttributes(shiftedAnchor, 0, bucket.text.dynamicVertices); - } - } - } - uploadPass.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); - } -} - template <typename DrawFn> void drawIcon(const DrawFn& draw, const RenderTile& tile, @@ -314,8 +186,7 @@ void drawText(const DrawFn& draw, const LayerRenderData& renderData, SegmentsWrapper textSegments, const SymbolBucket::PaintProperties& bucketPaintProperties, - const PaintParameters& parameters, - bool hasVariablePlacement) { + const PaintParameters& parameters) { assert(tile.tile.kind == Tile::Kind::Geometry); auto& geometryTile = static_cast<GeometryTile&>(tile.tile); auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket); @@ -335,7 +206,7 @@ void drawText(const DrawFn& draw, if (values.hasHalo) { draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, - SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), + SymbolSDFTextProgram::layoutUniformValues(true, bucket.hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.text, textSegments, bucket.textSizeBinder, @@ -350,7 +221,7 @@ void drawText(const DrawFn& draw, if (values.hasFill) { draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, - SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), + SymbolSDFTextProgram::layoutUniformValues(true, bucket.hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.text, textSegments, bucket.textSizeBinder, @@ -413,24 +284,6 @@ bool RenderSymbolLayer::hasCrossfade() const { return false; } -void RenderSymbolLayer::upload(gfx::UploadPass& uploadPass, UploadParameters& uploadParameters) { - for (const RenderTile& tile : renderTiles) { - const LayerRenderData* renderData = tile.tile.getLayerRenderData(*baseImpl); - if (!renderData) { - continue; - } - - auto& bucket = static_cast<SymbolBucket&>(*renderData->bucket); - if (bucket.hasIconData()) { - uploadIcon(uploadPass, uploadParameters, tile, *renderData); - } - - if (bucket.hasTextData()) { - uploadText(uploadPass, uploadParameters, tile, *renderData, hasVariablePlacement); - } - } -} - void RenderSymbolLayer::render(PaintParameters& parameters) { if (parameters.pass == RenderPass::Opaque) { return; @@ -537,7 +390,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { if (sortFeaturesByKey) { addRenderables(bucket.text.segments, true /*isText*/); } else { - drawText(draw, tile, *renderData, std::ref(bucket.text.segments), bucketPaintProperties, parameters, hasVariablePlacement); + drawText(draw, tile, *renderData, std::ref(bucket.text.segments), bucketPaintProperties, parameters); } } @@ -619,7 +472,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { if (sortFeaturesByKey) { for (auto& renderable : renderableSegments) { if (renderable.isText) { - drawText(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters, hasVariablePlacement); + drawText(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters); } else { drawIcon(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters); } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index ffd05aa310..d9ce8c688d 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -65,7 +65,6 @@ private: void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; bool hasCrossfade() const override; - void upload(gfx::UploadPass&, UploadParameters&) override; void render(PaintParameters&) override; void prepare(const LayerPrepareParameters&) override; @@ -76,7 +75,6 @@ private: float textSize = 16.0f; bool hasFormatSectionOverrides = false; - bool hasVariablePlacement = false; }; } // namespace mbgl diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index f8e6b65f7f..a809fd843a 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -345,10 +345,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { placement->setStale(); } - if (placementChanged || symbolBucketsChanged) { - for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { - placement->updateLayerOpacities(*it); - } + for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { + placement->updateLayerBuckets(*it, placementChanged || symbolBucketsChanged); } } @@ -385,7 +383,6 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { UploadParameters uploadParameters{ updateParameters.transformState, - placement->getVariableOffsets(), *imageManager, *lineAtlas, }; diff --git a/src/mbgl/renderer/upload_parameters.hpp b/src/mbgl/renderer/upload_parameters.hpp index 0328309927..14da1026c6 100644 --- a/src/mbgl/renderer/upload_parameters.hpp +++ b/src/mbgl/renderer/upload_parameters.hpp @@ -7,23 +7,18 @@ namespace mbgl { class TransformState; class LineAtlas; -class VariableOffset; -using VariableOffsets = std::unordered_map<uint32_t, VariableOffset>; class UploadParameters { public: UploadParameters(const TransformState& state_, - const VariableOffsets& variableOffsets_, ImageManager& imageManager_, LineAtlas& lineAtlas_) : state(state_), - variableOffsets(variableOffsets_), imageManager(imageManager_), lineAtlas(lineAtlas_) { } const TransformState& state; - const VariableOffsets& variableOffsets; ImageManager& imageManager; LineAtlas& lineAtlas; }; diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 49a57ae7c0..8dbb7fe346 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -396,10 +396,110 @@ void Placement::commit(TimePoint now) { fadeStartTime = placementChanged ? commitTime : prevPlacement->fadeStartTime; } -void Placement::updateLayerOpacities(const RenderLayer& layer) { +void Placement::updateLayerBuckets(const RenderLayer& layer, bool updateOpacities) { std::set<uint32_t> seenCrossTileIDs; for (const auto& item : layer.getPlacementData()) { - item.bucket.get().updateOpacities(*this, seenCrossTileIDs); + item.bucket.get().updateVertices(*this, updateOpacities, item.tile, seenCrossTileIDs); + } +} + +namespace { +Point<float> calculateVariableRenderShift(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale, float renderTextSize) { + AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); + float shiftX = -(alignment.horizontalAlign - 0.5f) * width; + float shiftY = -(alignment.verticalAlign - 0.5f) * height; + Point<float> offset = SymbolLayout::evaluateRadialOffset(anchor, radialOffset); + return { (shiftX / textBoxScale + offset.x) * renderTextSize, + (shiftY / textBoxScale + offset.y) * renderTextSize }; +} +} // namespace + +void Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const RenderTile& tile) { + using namespace style; + const auto& layout = bucket.layout; + const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point; + if (alongLine) { + if (bucket.hasIconData() && layout.get<IconRotationAlignment>() == AlignmentType::Map) { + const bool pitchWithMap = layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map; + const bool keepUpright = layout.get<style::IconKeepUpright>(); + reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols, + tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright, + tile, *bucket.iconSizeBinder, state); + } + + if (bucket.hasTextData() && layout.get<TextRotationAlignment>() == AlignmentType::Map) { + const bool pitchWithMap = layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map; + const bool keepUpright = layout.get<style::TextKeepUpright>(); + reprojectLineLabels(bucket.text.dynamicVertices, bucket.text.placedSymbols, + tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright, + tile, *bucket.textSizeBinder, state); + } + } else if (!layout.get<TextVariableAnchor>().empty() && bucket.hasTextData()) { + bucket.text.dynamicVertices.clear(); + bucket.hasVariablePlacement = false; + + const auto partiallyEvaluatedSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom()); + const float tileScale = std::pow(2, state.getZoom() - tile.tile.id.overscaledZ); + const bool rotateWithMap = layout.get<TextRotationAlignment>() == AlignmentType::Map; + const bool pitchWithMap = layout.get<TextPitchAlignment>() == AlignmentType::Map; + const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom()); + const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits); + + for (const PlacedSymbol& symbol : bucket.text.placedSymbols) { + optional<VariableOffset> variableOffset; + if (!symbol.hidden && symbol.crossTileID != 0u) { + auto it = variableOffsets.find(symbol.crossTileID); + if (it != variableOffsets.end()) { + bucket.hasVariablePlacement = true; + variableOffset = it->second; + } + } + + if (!variableOffset) { + // These symbols are from a justification that is not being used, or a label that wasn't placed + // so we don't need to do the extra math to figure out what incremental shift to apply. + hideGlyphs(symbol.glyphOffsets.size(), bucket.text.dynamicVertices); + } else { + const Point<float> tileAnchor = symbol.anchorPoint; + const auto projectedAnchor = project(tileAnchor, pitchWithMap ? tile.matrix : labelPlaneMatrix); + const float perspectiveRatio = 0.5f + 0.5f * (state.getCameraToCenterDistance() / projectedAnchor.second); + float renderTextSize = evaluateSizeForFeature(partiallyEvaluatedSize, symbol) * perspectiveRatio / util::ONE_EM; + if (pitchWithMap) { + // Go from size in pixels to equivalent size in tile units + renderTextSize *= bucket.tilePixelRatio / tileScale; + } + + auto shift = calculateVariableRenderShift( + (*variableOffset).anchor, + (*variableOffset).width, + (*variableOffset).height, + (*variableOffset).radialOffset, + (*variableOffset).textBoxScale, + renderTextSize); + + // Usual case is that we take the projected anchor and add the pixel-based shift + // calculated above. In the (somewhat weird) case of pitch-aligned text, we add an equivalent + // tile-unit based shift to the anchor before projecting to the label plane. + Point<float> shiftedAnchor; + if (pitchWithMap) { + shiftedAnchor = project(Point<float>(tileAnchor.x + shift.x, tileAnchor.y + shift.y), + labelPlaneMatrix).first; + } else { + if (rotateWithMap) { + auto rotated = util::rotate(shift, -state.getPitch()); + shiftedAnchor = Point<float>(projectedAnchor.first.x + rotated.x, + projectedAnchor.first.y + rotated.y); + } else { + shiftedAnchor = Point<float>(projectedAnchor.first.x + shift.x, + projectedAnchor.first.y + shift.y); + } + } + + for (std::size_t i = 0; i < symbol.glyphOffsets.size(); ++i) { + addDynamicAttributes(shiftedAnchor, 0, bucket.text.dynamicVertices); + } + } + } } } @@ -559,7 +659,6 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& } } - bucket.updateOpacity(); bucket.sortFeatures(state.getBearing()); auto retainedData = retainedQueryData.find(bucket.bucketInstanceId); if (retainedData != retainedQueryData.end()) { diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index e0fcac3350..c159286a2b 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -105,7 +105,7 @@ public: Placement(const TransformState&, MapMode, style::TransitionOptions, const bool crossSourceCollisions, std::unique_ptr<Placement> prevPlacementOrNull = nullptr); void placeLayer(const RenderLayer&, const mat4&, bool showCollisionBoxes); void commit(TimePoint); - void updateLayerOpacities(const RenderLayer&); + void updateLayerBuckets(const RenderLayer&, bool updateOpacities); float symbolFadeChange(TimePoint now) const; bool hasTransitions(TimePoint now) const; @@ -116,9 +116,6 @@ public: void setStale(); const RetainedQueryData& getQueryData(uint32_t bucketInstanceId) const; - using VariableOffsets = std::unordered_map<uint32_t, VariableOffset>; - const VariableOffsets& getVariableOffsets() const { return variableOffsets; } - private: friend SymbolBucket; void placeLayerBucket( @@ -126,6 +123,7 @@ private: const BucketPlacementParameters&, std::set<uint32_t>& seenCrossTileIDs); + void updateBucketDynamicVertices(SymbolBucket& bucket, const RenderTile& tile); void updateBucketOpacities(SymbolBucket&, std::set<uint32_t>&); void markUsedJustification(SymbolBucket&, style::TextVariableAnchorType, SymbolInstance&); |