From 66d05a7ce833aab69a82ac275580172cf461d4c5 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Sun, 4 Aug 2019 15:48:12 +0300 Subject: [PATCH 1/5] [core] Fix placement for updated buckets Buckets update initiates new placement, so that newly added symbols are placed and shown immediately. --- src/mbgl/renderer/render_orchestrator.cpp | 18 ++++++++---------- src/mbgl/text/placement.cpp | 8 ++------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 983bc094852..eb6963c9705 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -361,26 +361,24 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar } bool symbolBucketsChanged = false; - renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom()); + for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { + if (crossTileSymbolIndex.addLayer(*it, updateParameters.transformState.getLatLng().longitude())) symbolBucketsChanged = true; + } + renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom()) || symbolBucketsChanged; + std::set usedSymbolLayers; if (renderTreeParameters->placementChanged) { placement = std::make_unique( updateParameters.transformState, updateParameters.mode, updateParameters.transitionOptions, updateParameters.crossSourceCollisions, std::move(placement)); - } - for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { - const RenderLayer& layer = *it; - if (crossTileSymbolIndex.addLayer(layer, updateParameters.transformState.getLatLng().longitude())) symbolBucketsChanged = true; - - if (renderTreeParameters->placementChanged) { + for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { + const RenderLayer& layer = *it; usedSymbolLayers.insert(layer.getID()); placement->placeLayer(layer, renderTreeParameters->transformParams.projMatrix, updateParameters.debugOptions & MapDebugOptions::Collision); } - } - if (renderTreeParameters->placementChanged) { placement->commit(updateParameters.timePoint, updateParameters.transformState.getZoom()); crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers); for (const auto& entry : renderSources) { @@ -391,7 +389,7 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar } for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { - placement->updateLayerBuckets(*it, updateParameters.transformState, renderTreeParameters->placementChanged || symbolBucketsChanged); + placement->updateLayerBuckets(*it, updateParameters.transformState, renderTreeParameters->placementChanged); } renderTreeParameters->symbolFadeChange = placement->symbolFadeChange(updateParameters.timePoint); diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index a8c0a1bd441..89b3189b836 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -699,7 +699,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState if (bucket.hasTextCollisionBoxData()) bucket.textCollisionBox->dynamicVertices.clear(); if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle->dynamicVertices.clear(); - JointOpacityState duplicateOpacityState(false, false, true); + const JointOpacityState duplicateOpacityState(false, false, true); const bool textAllowOverlap = bucket.layout->get(); const bool iconAllowOverlap = bucket.layout->get(); @@ -712,7 +712,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState // But we have to wait for placement if we potentially depend on a paired icon/text // with allow-overlap: false. // See https://github.com/mapbox/mapbox-gl-native/issues/12483 - JointOpacityState defaultOpacityState( + const JointOpacityState defaultOpacityState( textAllowOverlap && (iconAllowOverlap || !(bucket.hasIconData() || bucket.hasSdfIconData()) || bucket.layout->get()), iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || bucket.layout->get()), true); @@ -728,10 +728,6 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState opacityState = it->second; } - if (it == opacities.end()) { - opacities.emplace(symbolInstance.crossTileID, defaultOpacityState); - } - seenCrossTileIDs.insert(symbolInstance.crossTileID); if (symbolInstance.hasText()) { From 877152e5a0196f88e3bc7aa469151af868da084e Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 10 Sep 2019 16:18:54 +0300 Subject: [PATCH 2/5] [core] Bitmask operations for enums --- include/mbgl/storage/resource.hpp | 18 ++----------- include/mbgl/util/bitmask_operations.hpp | 33 ++++++++++++++++++++++++ src/core-files.json | 1 + src/mbgl/layout/symbol_instance.hpp | 15 +---------- src/mbgl/renderer/render_layer.cpp | 2 +- src/mbgl/renderer/render_pass.hpp | 15 +---------- src/mbgl/text/glyph.hpp | 21 +-------------- 7 files changed, 40 insertions(+), 65 deletions(-) create mode 100644 include/mbgl/util/bitmask_operations.hpp diff --git a/include/mbgl/storage/resource.hpp b/include/mbgl/storage/resource.hpp index 40c4c836b1b..d00f336669e 100644 --- a/include/mbgl/storage/resource.hpp +++ b/include/mbgl/storage/resource.hpp @@ -1,11 +1,10 @@ #pragma once #include +#include #include #include #include -#include -#include #include @@ -98,21 +97,8 @@ class Resource { std::shared_ptr priorData; }; - -MBGL_CONSTEXPR Resource::LoadingMethod operator|(Resource::LoadingMethod a, Resource::LoadingMethod b) { - return Resource::LoadingMethod(mbgl::underlying_type(a) | mbgl::underlying_type(b)); -} - -MBGL_CONSTEXPR Resource::LoadingMethod& operator|=(Resource::LoadingMethod& a, Resource::LoadingMethod b) { - return (a = a | b); -} - -MBGL_CONSTEXPR Resource::LoadingMethod operator&(Resource::LoadingMethod a, Resource::LoadingMethod b) { - return Resource::LoadingMethod(mbgl::underlying_type(a) & mbgl::underlying_type(b)); -} - inline bool Resource::hasLoadingMethod(Resource::LoadingMethod method) { - return (loadingMethod & method) != Resource::LoadingMethod::None; + return (loadingMethod & method); } } // namespace mbgl diff --git a/include/mbgl/util/bitmask_operations.hpp b/include/mbgl/util/bitmask_operations.hpp new file mode 100644 index 00000000000..014fabdea25 --- /dev/null +++ b/include/mbgl/util/bitmask_operations.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace mbgl { + +template +MBGL_CONSTEXPR Enum operator|(Enum a, Enum b) { + static_assert(std::is_enum::value, "Enum must be an enum type"); + return Enum(mbgl::underlying_type(a) | mbgl::underlying_type(b)); +} + +template +MBGL_CONSTEXPR Enum& operator|=(Enum& a, Enum b) { + static_assert(std::is_enum::value, "Enum must be an enum type"); + return (a = a | b); +} + +template +MBGL_CONSTEXPR bool operator&(Enum a, Enum b) { + static_assert(std::is_enum::value, "Enum must be an enum type"); + return bool(mbgl::underlying_type(a) & mbgl::underlying_type(b)); +} + +template +MBGL_CONSTEXPR Enum operator~(Enum value) { + static_assert(std::is_enum::value, "Enum must be an enum type"); + return Enum(~mbgl::underlying_type(value)); +} + + +} // namespace mbgl \ No newline at end of file diff --git a/src/core-files.json b/src/core-files.json index 628ab5e3a7b..9453e504bbc 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -456,6 +456,7 @@ "mbgl/tile/tile_necessity.hpp": "include/mbgl/tile/tile_necessity.hpp", "mbgl/util/async_request.hpp": "include/mbgl/util/async_request.hpp", "mbgl/util/async_task.hpp": "include/mbgl/util/async_task.hpp", + "mbgl/util/bitmask_operations.hpp": "include/mbgl/util/bitmask_operations.hpp", "mbgl/util/char_array_buffer.hpp": "include/mbgl/util/char_array_buffer.hpp", "mbgl/util/chrono.hpp": "include/mbgl/util/chrono.hpp", "mbgl/util/color.hpp": "include/mbgl/util/color.hpp", diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 3e2ab5f8b33..4a57b527f7b 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include namespace mbgl { @@ -50,18 +49,6 @@ enum class SymbolContent : uint8_t { IconSDF = 1 << 2 }; -MBGL_CONSTEXPR SymbolContent operator|(SymbolContent a, SymbolContent b) { - return SymbolContent(mbgl::underlying_type(a) | mbgl::underlying_type(b)); -} - -MBGL_CONSTEXPR SymbolContent& operator|=(SymbolContent& a, SymbolContent b) { - return (a = a | b); -} - -MBGL_CONSTEXPR SymbolContent operator&(SymbolContent a, SymbolContent b) { - return SymbolContent(mbgl::underlying_type(a) & mbgl::underlying_type(b)); -} - class SymbolInstance { public: SymbolInstance(Anchor& anchor_, diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index c1ca1fd017e..fe1b151b585 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -32,7 +32,7 @@ const std::string& RenderLayer::getID() const { } bool RenderLayer::hasRenderPass(RenderPass pass) const { - return bool(passes & pass); + return passes & pass; } bool RenderLayer::needsRendering() const { diff --git a/src/mbgl/renderer/render_pass.hpp b/src/mbgl/renderer/render_pass.hpp index 5d18304129d..4d1b1f91f96 100644 --- a/src/mbgl/renderer/render_pass.hpp +++ b/src/mbgl/renderer/render_pass.hpp @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include #include @@ -14,18 +13,6 @@ enum class RenderPass : uint8_t { Pass3D = 1 << 2, }; -MBGL_CONSTEXPR RenderPass operator|(RenderPass a, RenderPass b) { - return RenderPass(mbgl::underlying_type(a) | mbgl::underlying_type(b)); -} - -MBGL_CONSTEXPR RenderPass& operator|=(RenderPass& a, RenderPass b) { - return (a = a | b); -} - -MBGL_CONSTEXPR RenderPass operator&(RenderPass a, RenderPass b) { - return RenderPass(mbgl::underlying_type(a) & mbgl::underlying_type(b)); -} - // Defines whether the overdraw shaders should be used instead of the regular shaders. enum class PaintMode : bool { Regular = false, diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index 234f718975f..ba9c521f77b 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -99,26 +100,6 @@ enum class WritingModeType : uint8_t { Vertical = 1 << 1, }; -MBGL_CONSTEXPR WritingModeType operator|(WritingModeType a, WritingModeType b) { - return WritingModeType(mbgl::underlying_type(a) | mbgl::underlying_type(b)); -} - -MBGL_CONSTEXPR WritingModeType& operator|=(WritingModeType& a, WritingModeType b) { - return (a = a | b); -} - -MBGL_CONSTEXPR bool operator&(WritingModeType lhs, WritingModeType rhs) { - return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs); -} - -MBGL_CONSTEXPR WritingModeType& operator&=(WritingModeType& lhs, WritingModeType rhs) { - return (lhs = WritingModeType(mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs))); -} - -MBGL_CONSTEXPR WritingModeType operator~(WritingModeType value) { - return WritingModeType(~mbgl::underlying_type(value)); -} - using GlyphDependencies = std::map; using GlyphRangeDependencies = std::map>; From 8b8a2f4dfa607dde6d9b92e2f8c8b5849efe144e Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 10 Sep 2019 16:25:14 +0300 Subject: [PATCH 3/5] [core] Initiate new placement only when a new bucket appeares --- src/mbgl/renderer/render_orchestrator.cpp | 9 ++++++--- src/mbgl/text/cross_tile_symbol_index.cpp | 19 +++++++++---------- src/mbgl/text/cross_tile_symbol_index.hpp | 9 ++++++++- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index eb6963c9705..1e2541c4d4b 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -360,11 +360,14 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar crossTileSymbolIndex.reset(); } + bool symbolBucketsAdded = false; bool symbolBucketsChanged = false; for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { - if (crossTileSymbolIndex.addLayer(*it, updateParameters.transformState.getLatLng().longitude())) symbolBucketsChanged = true; + auto result = crossTileSymbolIndex.addLayer(*it, updateParameters.transformState.getLatLng().longitude()); + symbolBucketsAdded = symbolBucketsAdded || (result & CrossTileSymbolIndex::AddLayerResult::BucketsAdded); + symbolBucketsChanged = symbolBucketsChanged || (result != CrossTileSymbolIndex::AddLayerResult::NoChanges); } - renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom()) || symbolBucketsChanged; + renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom()) || symbolBucketsAdded; std::set usedSymbolLayers; if (renderTreeParameters->placementChanged) { @@ -389,7 +392,7 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar } for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { - placement->updateLayerBuckets(*it, updateParameters.transformState, renderTreeParameters->placementChanged); + placement->updateLayerBuckets(*it, updateParameters.transformState, renderTreeParameters->placementChanged || symbolBucketsChanged); } renderTreeParameters->symbolFadeChange = placement->symbolFadeChange(updateParameters.timePoint); diff --git a/src/mbgl/text/cross_tile_symbol_index.cpp b/src/mbgl/text/cross_tile_symbol_index.cpp index 43ed85d957a..55ab2cc3c53 100644 --- a/src/mbgl/text/cross_tile_symbol_index.cpp +++ b/src/mbgl/text/cross_tile_symbol_index.cpp @@ -163,10 +163,10 @@ bool CrossTileSymbolLayerIndex::removeStaleBuckets(const std::unordered_set AddLayerResult { auto& layerIndex = layerIndexes[layer.getID()]; - bool symbolBucketsChanged = false; + AddLayerResult result = AddLayerResult::NoChanges; std::unordered_set currentBucketIDs; layerIndex.handleWrapJump(lng); @@ -174,16 +174,15 @@ bool CrossTileSymbolIndex::addLayer(const RenderLayer& layer, float lng) { for (const auto& item : layer.getPlacementData()) { const RenderTile& renderTile = item.tile; Bucket& bucket = item.bucket; - auto result = bucket.registerAtCrossTileIndex(layerIndex, renderTile.getOverscaledTileID(), maxCrossTileID); - assert(result.first != 0u); - symbolBucketsChanged = symbolBucketsChanged || result.second; - currentBucketIDs.insert(result.first); + auto pair = bucket.registerAtCrossTileIndex(layerIndex, renderTile.getOverscaledTileID(), maxCrossTileID); + assert(pair.first != 0u); + if (pair.second) result |= AddLayerResult::BucketsAdded; + currentBucketIDs.insert(pair.first); } - if (layerIndex.removeStaleBuckets(currentBucketIDs)) { - symbolBucketsChanged = true; - } - return symbolBucketsChanged; + if (layerIndex.removeStaleBuckets(currentBucketIDs)) result |= AddLayerResult::BucketsRemoved; + + return result; } void CrossTileSymbolIndex::pruneUnusedLayers(const std::set& usedLayers) { diff --git a/src/mbgl/text/cross_tile_symbol_index.hpp b/src/mbgl/text/cross_tile_symbol_index.hpp index d905aeb569e..4e32698b3ea 100644 --- a/src/mbgl/text/cross_tile_symbol_index.hpp +++ b/src/mbgl/text/cross_tile_symbol_index.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -58,7 +59,13 @@ class CrossTileSymbolIndex { public: CrossTileSymbolIndex(); - bool addLayer(const RenderLayer& layer, float lng); + enum class AddLayerResult : uint8_t { + NoChanges = 0, + BucketsAdded = 1 << 0, + BucketsRemoved = 1 << 1 + }; + + AddLayerResult addLayer(const RenderLayer& layer, float lng); void pruneUnusedLayers(const std::set&); void reset(); From 4ee7d991d9116d9df95cfa0840810ff70ca1894f Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 13 Sep 2019 11:21:27 +0300 Subject: [PATCH 4/5] [core] Coalesce buckets updates from several tiles --- src/mbgl/renderer/render_orchestrator.cpp | 6 +++++- src/mbgl/text/placement.cpp | 20 ++++++++++++++++---- src/mbgl/text/placement.hpp | 4 +++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 1e2541c4d4b..a62ccb0a0ae 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -367,7 +367,11 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar symbolBucketsAdded = symbolBucketsAdded || (result & CrossTileSymbolIndex::AddLayerResult::BucketsAdded); symbolBucketsChanged = symbolBucketsChanged || (result != CrossTileSymbolIndex::AddLayerResult::NoChanges); } - renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom()) || symbolBucketsAdded; + // We want new symbols to show up faster, however simple setting `placementChanged` to `true` would + // initiate placement too often as new buckets ususally come from several rendered tiles in a row within + // a short period of time. Instead, we squeeze placement update period to coalesce buckets updates from several tiles. + if (symbolBucketsAdded) placement->setMaximumUpdatePeriod(Milliseconds(30)); + renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom()); std::set usedSymbolLayers; if (renderTreeParameters->placementChanged) { diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 89b3189b836..06777dea44a 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -964,6 +964,17 @@ float Placement::zoomAdjustment(const float zoom) const { return std::max(0.0, (placementZoom - zoom) / 1.5); } +Duration Placement::getUpdatePeriod(const float zoom) const { + // Even if transitionOptions.duration is set to a value < 300ms, we still wait for this default transition duration + // before attempting another placement operation. + const auto fadeDuration = std::max(util::DEFAULT_TRANSITION_DURATION, transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION)); + const auto adjustedDuration = std::chrono::duration_cast(fadeDuration * (1.0 - zoomAdjustment(zoom))); + if (maximumUpdatePeriod) { + return std::min(*maximumUpdatePeriod, adjustedDuration); + } + return adjustedDuration; +} + bool Placement::hasTransitions(TimePoint now) const { if (mapMode == MapMode::Continuous && transitionOptions.enablePlacementTransitions) { return stale || std::chrono::duration(now - fadeStartTime) < transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION); @@ -973,12 +984,13 @@ bool Placement::hasTransitions(TimePoint now) const { } bool Placement::stillRecent(TimePoint now, const float zoom) const { - // Even if transitionOptions.duration is set to a value < 300ms, we still wait for this default transition duration - // before attempting another placement operation. - const auto fadeDuration = std::max(util::DEFAULT_TRANSITION_DURATION, transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION)); return mapMode == MapMode::Continuous && transitionOptions.enablePlacementTransitions && - commitTime + fadeDuration * (1.0 - zoomAdjustment(zoom)) > now; + commitTime + getUpdatePeriod(zoom) > now; +} + +void Placement::setMaximumUpdatePeriod(Duration duration) { + maximumUpdatePeriod = duration; } void Placement::setStale() { diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index c1fe69b8527..b5405cbcd7b 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -110,7 +110,7 @@ class Placement { const CollisionIndex& getCollisionIndex() const; bool stillRecent(TimePoint now, const float zoom) const; - void setRecent(TimePoint now); + void setMaximumUpdatePeriod(Duration); void setStale(); const RetainedQueryData& getQueryData(uint32_t bucketInstanceId) const; @@ -126,6 +126,7 @@ class Placement { void markUsedJustification(SymbolBucket&, style::TextVariableAnchorType, const SymbolInstance&, style::TextWritingModeType orientation); void markUsedOrientation(SymbolBucket&, style::TextWritingModeType, const SymbolInstance&); float zoomAdjustment(const float zoom) const; + Duration getUpdatePeriod(const float zoom) const; CollisionIndex collisionIndex; @@ -147,6 +148,7 @@ class Placement { std::unordered_map retainedQueryData; CollisionGroups collisionGroups; std::unique_ptr prevPlacement; + optional maximumUpdatePeriod; // Used for debug purposes. std::unordered_map> collisionCircles; From 2fb0bc2b0b566c34ad04940b7297b29b32c3f0c9 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 13 Sep 2019 13:15:09 +0300 Subject: [PATCH 5/5] [ios][android] Add a change log entry --- platform/android/CHANGELOG.md | 3 +++ platform/ios/CHANGELOG.md | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 9ad600b16e0..7c6b28ee165 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -11,6 +11,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## 8.4.0-alpha.2 - September 11, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1): +### Performance improvements + - Newly loaded labels appear faster on the screen. [#15308](https://github.com/mapbox/mapbox-gl-native/pull/15308) + ### Bug fixes - Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. [#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 15f5904b5d5..2e81bbed323 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,6 +2,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. +## master + +### Performance improvements + +* Newly loaded labels appear faster on the screen. ([#15308](https://github.com/mapbox/mapbox-gl-native/pull/15308)) + ## 5.4.0 ### Styles and rendering