diff options
Diffstat (limited to 'src/mbgl/tile')
-rw-r--r-- | src/mbgl/tile/geojson_tile.cpp | 51 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile.cpp | 165 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile.hpp | 75 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_data.hpp | 9 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_worker.cpp | 130 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_worker.hpp | 29 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile.cpp | 22 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile.hpp | 11 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile_worker.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/tile/tile.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/tile/tile.hpp | 18 | ||||
-rw-r--r-- | src/mbgl/tile/tile_id.hpp | 275 | ||||
-rw-r--r-- | src/mbgl/tile/tile_id_hash.cpp | 29 | ||||
-rw-r--r-- | src/mbgl/tile/tile_id_io.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/tile/tile_loader_impl.hpp | 3 | ||||
-rw-r--r-- | src/mbgl/tile/vector_tile.cpp | 299 | ||||
-rw-r--r-- | src/mbgl/tile/vector_tile_data.cpp | 89 | ||||
-rw-r--r-- | src/mbgl/tile/vector_tile_data.hpp | 54 |
18 files changed, 521 insertions, 752 deletions
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 3c4939a0a6..5d8339d775 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -1,8 +1,9 @@ #include <mbgl/tile/geojson_tile.hpp> #include <mbgl/tile/geometry_tile_data.hpp> -#include <mbgl/map/query.hpp> -#include <mbgl/style/style.hpp> +#include <mbgl/renderer/query.hpp> #include <mbgl/renderer/tile_parameters.hpp> +#include <mbgl/style/filter_evaluator.hpp> +#include <mbgl/util/string.hpp> #include <mapbox/geojsonvt.hpp> #include <supercluster.hpp> @@ -52,43 +53,57 @@ public: } }; -class GeoJSONTileData : public GeometryTileData, - public GeometryTileLayer { +class GeoJSONTileLayer : public GeometryTileLayer { public: - mapbox::geometry::feature_collection<int16_t> features; - - GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_) + GeoJSONTileLayer(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_) : features(std::move(features_)) { } - std::unique_ptr<GeometryTileData> clone() const override { - return std::make_unique<GeoJSONTileData>(*this); + std::size_t featureCount() const override { + return features->size(); } - const GeometryTileLayer* getLayer(const std::string&) const override { - return this; + std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override { + return std::make_unique<GeoJSONTileFeature>((*features)[i]); } std::string getName() const override { return ""; } - std::size_t featureCount() const override { - return features.size(); +private: + std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features; +}; + +class GeoJSONTileData : public GeometryTileData { +public: + GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_) + : features(std::make_shared<mapbox::geometry::feature_collection<int16_t>>( + std::move(features_))) { } - std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override { - return std::make_unique<GeoJSONTileFeature>(features[i]); + GeoJSONTileData(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_) + : features(std::move(features_)) { + } + + std::unique_ptr<GeometryTileData> clone() const override { + return std::make_unique<GeoJSONTileData>(features); } + + std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const override { + return std::make_unique<GeoJSONTileLayer>(features); + } + + +private: + std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features; }; GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID, std::string sourceID_, const TileParameters& parameters, mapbox::geometry::feature_collection<int16_t> features) - : GeometryTile(overscaledTileID, sourceID_, parameters, - *parameters.style.glyphAtlas, - *parameters.style.spriteAtlas) { + : GeometryTile(overscaledTileID, sourceID_, parameters) { updateData(std::move(features)); } diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 23b3737a38..8c018ce3aa 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -6,20 +6,20 @@ #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/custom_layer.hpp> #include <mbgl/renderer/tile_parameters.hpp> -#include <mbgl/renderer/render_background_layer.hpp> -#include <mbgl/renderer/render_custom_layer.hpp> -#include <mbgl/renderer/render_symbol_layer.hpp> -#include <mbgl/renderer/symbol_bucket.hpp> -#include <mbgl/style/style.hpp> +#include <mbgl/renderer/layers/render_background_layer.hpp> +#include <mbgl/renderer/layers/render_custom_layer.hpp> +#include <mbgl/renderer/layers/render_symbol_layer.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> +#include <mbgl/renderer/query.hpp> +#include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/renderer/image_atlas.hpp> #include <mbgl/storage/file_source.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/text/collision_tile.hpp> #include <mbgl/map/transform_state.hpp> -#include <mbgl/map/query.hpp> -#include <mbgl/util/run_loop.hpp> #include <mbgl/style/filter_evaluator.hpp> -#include <mbgl/util/chrono.hpp> #include <mbgl/util/logging.hpp> +#include <mbgl/actor/scheduler.hpp> #include <iostream> @@ -27,32 +27,51 @@ namespace mbgl { using namespace style; +/* + Correlation between GeometryTile and GeometryTileWorker is safeguarded by two + correlation schemes: + + GeometryTile's 'correlationID' is used for ensuring the tile will be flagged + as non-pending only when the placement coming from the last operation (as in + 'setData', 'setLayers', 'setPlacementConfig') occurs. This is important for + still mode rendering as we want to render only when all layout and placement + operations are completed. + + GeometryTileWorker's 'imageCorrelationID' is used for checking whether an + image request reply coming from `GeometryTile` is valid. Previous image + request replies are ignored as they result in incomplete placement attempts + that could flag the tile as non-pending too early. + */ + GeometryTile::GeometryTile(const OverscaledTileID& id_, std::string sourceID_, - const TileParameters& parameters, - GlyphAtlas& glyphAtlas_, - SpriteAtlas& spriteAtlas_) + const TileParameters& parameters) : Tile(id_), sourceID(std::move(sourceID_)), - style(parameters.style), - mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())), + mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())), worker(parameters.workerScheduler, ActorRef<GeometryTile>(*this, mailbox), id_, obsolete, - parameters.mode), - glyphAtlas(glyphAtlas_), - spriteAtlas(spriteAtlas_), - placementThrottler(Milliseconds(300), [this] { invokePlacement(); }) { + parameters.mode, + parameters.pixelRatio), + glyphManager(parameters.glyphManager), + imageManager(parameters.imageManager), + lastYStretch(1.0f), + mode(parameters.mode) { } GeometryTile::~GeometryTile() { - glyphAtlas.removeGlyphs(*this); - spriteAtlas.removeRequestor(*this); - cancel(); + glyphManager.removeRequestor(*this); + imageManager.removeRequestor(*this); + markObsolete(); } void GeometryTile::cancel() { + markObsolete(); +} + +void GeometryTile::markObsolete() { obsolete = true; } @@ -68,7 +87,6 @@ void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) { ++correlationID; worker.invoke(&GeometryTileWorker::setData, std::move(data_), correlationID); - redoLayout(); } void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) { @@ -82,7 +100,7 @@ void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) { ++correlationID; requestedConfig = desiredConfig; - placementThrottler.invoke(); + invokePlacement(); } void GeometryTile::invokePlacement() { @@ -91,29 +109,29 @@ void GeometryTile::invokePlacement() { } } -void GeometryTile::redoLayout() { +void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers) { // Mark the tile as pending again if it was complete before to prevent signaling a complete // state despite pending parse operations. pending = true; - std::vector<std::unique_ptr<Layer>> copy; + std::vector<Immutable<Layer::Impl>> impls; - for (const Layer* layer : style.getLayers()) { - // Avoid cloning and including irrelevant layers. - if (layer->is<BackgroundLayer>() || - layer->is<CustomLayer>() || - layer->baseImpl->source != sourceID || - id.overscaledZ < std::floor(layer->baseImpl->minZoom) || - id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom) || - layer->baseImpl->visibility == VisibilityType::None) { + for (const auto& layer : layers) { + // Skip irrelevant layers. + if (layer->type == LayerType::Background || + layer->type == LayerType::Custom || + layer->source != sourceID || + id.overscaledZ < std::floor(layer->minZoom) || + id.overscaledZ >= std::ceil(layer->maxZoom) || + layer->visibility == VisibilityType::None) { continue; } - copy.push_back(layer->baseImpl->clone()); + impls.push_back(layer); } ++correlationID; - worker.invoke(&GeometryTileWorker::setLayers, std::move(copy), correlationID); + worker.invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID); } void GeometryTile::onLayout(LayoutResult result, const uint64_t resultCorrelationID) { @@ -134,10 +152,16 @@ void GeometryTile::onPlacement(PlacementResult result, const uint64_t resultCorr pending = false; } symbolBuckets = std::move(result.symbolBuckets); - for (auto& entry : symbolBuckets) { - dynamic_cast<SymbolBucket*>(entry.second.get())->spriteAtlas = &spriteAtlas; - } collisionTile = std::move(result.collisionTile); + if (result.glyphAtlasImage) { + glyphAtlasImage = std::move(*result.glyphAtlasImage); + } + if (result.iconAtlasImage) { + iconAtlasImage = std::move(*result.iconAtlasImage); + } + if (collisionTile.get()) { + lastYStretch = collisionTile->yStretch; + } observer->onTileChanged(*this); } @@ -149,25 +173,51 @@ void GeometryTile::onError(std::exception_ptr err, const uint64_t resultCorrelat observer->onTileError(*this, err); } -void GeometryTile::onGlyphsAvailable(GlyphPositionMap glyphPositions) { - worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphPositions)); +void GeometryTile::onGlyphsAvailable(GlyphMap glyphs) { + worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs)); } void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { - glyphAtlas.getGlyphs(*this, std::move(glyphDependencies)); + glyphManager.getGlyphs(*this, std::move(glyphDependencies)); } -void GeometryTile::onIconsAvailable(IconMap icons) { - worker.invoke(&GeometryTileWorker::onIconsAvailable, std::move(icons)); +void GeometryTile::onImagesAvailable(ImageMap images, uint64_t imageCorrelationID) { + worker.invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), imageCorrelationID); } -void GeometryTile::getIcons(IconDependencies) { - spriteAtlas.getIcons(*this); +void GeometryTile::getImages(ImageRequestPair pair) { + imageManager.getImages(*this, std::move(pair)); } -Bucket* GeometryTile::getBucket(const RenderLayer& layer) const { - const auto& buckets = layer.is<RenderSymbolLayer>() ? symbolBuckets : nonSymbolBuckets; - const auto it = buckets.find(layer.baseImpl.id); +void GeometryTile::upload(gl::Context& context) { + auto uploadFn = [&] (Bucket& bucket) { + if (bucket.needsUpload()) { + bucket.upload(context); + } + }; + + for (auto& entry : nonSymbolBuckets) { + uploadFn(*entry.second); + } + + for (auto& entry : symbolBuckets) { + uploadFn(*entry.second); + } + + if (glyphAtlasImage) { + glyphAtlasTexture = context.createTexture(*glyphAtlasImage, 0); + glyphAtlasImage = {}; + } + + if (iconAtlasImage) { + iconAtlasTexture = context.createTexture(*iconAtlasImage, 0); + iconAtlasImage = {}; + } +} + +Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const { + const auto& buckets = layer.type == LayerType::Symbol ? symbolBuckets : nonSymbolBuckets; + const auto it = buckets.find(layer.id); if (it == buckets.end()) { return nullptr; } @@ -180,10 +230,20 @@ void GeometryTile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState& transformState, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) { if (!featureIndex || !data) return; + // Determine the additional radius needed factoring in property functions + float additionalRadius = 0; + for (const RenderLayer* layer : layers) { + auto bucket = getBucket(*layer->baseImpl); + if (bucket) { + additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(*layer)); + } + } + featureIndex->query(result, queryGeometry, transformState.getAngle(), @@ -192,9 +252,9 @@ void GeometryTile::queryRenderedFeatures( options, *data, id.canonical, - style, + layers, collisionTile.get(), - *this); + additionalRadius); } void GeometryTile::querySourceFeatures( @@ -233,4 +293,11 @@ void GeometryTile::querySourceFeatures( } } +float GeometryTile::yStretch() const { + // collisionTile gets reset in onLayout but we don't clear the symbolBuckets + // until a new placement result comes along, so keep the yStretch value in + // case we need to render them. + return lastYStretch; +} + } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 910cb446a0..a478aad504 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -1,13 +1,15 @@ #pragma once -#include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/tile/tile.hpp> #include <mbgl/tile/geometry_tile_worker.hpp> -#include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/renderer/image_manager.hpp> +#include <mbgl/text/glyph_manager.hpp> #include <mbgl/text/placement_config.hpp> +#include <mbgl/text/collision_tile.hpp> #include <mbgl/util/feature.hpp> #include <mbgl/util/throttler.hpp> #include <mbgl/actor/actor.hpp> +#include <mbgl/geometry/feature_index.hpp> #include <atomic> #include <memory> @@ -17,23 +19,17 @@ namespace mbgl { class GeometryTileData; -class FeatureIndex; -class CollisionTile; class RenderLayer; class SourceQueryOptions; class TileParameters; +class GlyphAtlas; +class ImageAtlas; -namespace style { -class Style; -} // namespace style - -class GeometryTile : public Tile, public GlyphRequestor, IconRequestor { +class GeometryTile : public Tile, public GlyphRequestor, ImageRequestor { public: GeometryTile(const OverscaledTileID&, std::string sourceID, - const TileParameters&, - GlyphAtlas&, - SpriteAtlas&); + const TileParameters&); ~GeometryTile() override; @@ -41,20 +37,25 @@ public: void setData(std::unique_ptr<const GeometryTileData>); void setPlacementConfig(const PlacementConfig&) override; - void redoLayout() override; + void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) override; - void onGlyphsAvailable(GlyphPositionMap) override; - void onIconsAvailable(IconMap) override; + void onGlyphsAvailable(GlyphMap) override; + void onImagesAvailable(ImageMap, uint64_t imageCorrelationID) override; void getGlyphs(GlyphDependencies); - void getIcons(IconDependencies); + void getImages(ImageRequestPair); + + void upload(gl::Context&) override; + Bucket* getBucket(const style::Layer::Impl&) const override; - Bucket* getBucket(const RenderLayer&) const override; + Size bindGlyphAtlas(gl::Context&); + Size bindIconAtlas(gl::Context&); void queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, + const std::vector<const RenderLayer*>& layers, const RenderedQueryOptions& options) override; void querySourceFeatures( @@ -68,6 +69,13 @@ public: std::unordered_map<std::string, std::shared_ptr<Bucket>> nonSymbolBuckets; std::unique_ptr<FeatureIndex> featureIndex; std::unique_ptr<GeometryTileData> tileData; + + LayoutResult(std::unordered_map<std::string, std::shared_ptr<Bucket>> nonSymbolBuckets_, + std::unique_ptr<FeatureIndex> featureIndex_, + std::unique_ptr<GeometryTileData> tileData_) + : nonSymbolBuckets(std::move(nonSymbolBuckets_)), + featureIndex(std::move(featureIndex_)), + tileData(std::move(tileData_)) {} }; void onLayout(LayoutResult, uint64_t correlationID); @@ -75,21 +83,34 @@ public: public: std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets; std::unique_ptr<CollisionTile> collisionTile; + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; + + PlacementResult(std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets_, + std::unique_ptr<CollisionTile> collisionTile_, + optional<AlphaImage> glyphAtlasImage_, + optional<PremultipliedImage> iconAtlasImage_) + : symbolBuckets(std::move(symbolBuckets_)), + collisionTile(std::move(collisionTile_)), + glyphAtlasImage(std::move(glyphAtlasImage_)), + iconAtlasImage(std::move(iconAtlasImage_)) {} }; void onPlacement(PlacementResult, uint64_t correlationID); void onError(std::exception_ptr, uint64_t correlationID); + float yStretch() const override; + protected: const GeometryTileData* getData() { return data.get(); } private: + void markObsolete(); void invokePlacement(); - + const std::string sourceID; - style::Style& style; // Used to signal the worker that it should abandon parsing this tile as soon as possible. std::atomic<bool> obsolete { false }; @@ -97,8 +118,8 @@ private: std::shared_ptr<Mailbox> mailbox; Actor<GeometryTileWorker> worker; - GlyphAtlas& glyphAtlas; - SpriteAtlas& spriteAtlas; + GlyphManager& glyphManager; + ImageManager& imageManager; uint64_t correlationID = 0; optional<PlacementConfig> requestedConfig; @@ -107,10 +128,18 @@ private: std::unique_ptr<FeatureIndex> featureIndex; std::unique_ptr<const GeometryTileData> data; + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; + std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets; std::unique_ptr<CollisionTile> collisionTile; - - util::Throttler placementThrottler; + + float lastYStretch; + const MapMode mode; + +public: + optional<gl::Texture> glyphAtlasTexture; + optional<gl::Texture> iconAtlasTexture; }; } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp index 285f86cc7b..449d8cab28 100644 --- a/src/mbgl/tile/geometry_tile_data.hpp +++ b/src/mbgl/tile/geometry_tile_data.hpp @@ -51,7 +51,11 @@ class GeometryTileLayer { public: virtual ~GeometryTileLayer() = default; virtual std::size_t featureCount() const = 0; + + // Returns the feature object at the given position within the layer. The returned feature + // object may *not* outlive the layer object. virtual std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const = 0; + virtual std::string getName() const = 0; }; @@ -59,7 +63,10 @@ class GeometryTileData { public: virtual ~GeometryTileData() = default; virtual std::unique_ptr<GeometryTileData> clone() const = 0; - virtual const GeometryTileLayer* getLayer(const std::string&) const = 0; + + // Returns the layer with the given name. The returned layer object *may* outlive the data + // object. + virtual std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const = 0; }; // classifies an array of rings into polygons with outer rings and holes diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 25834914c4..50429420c3 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -3,14 +3,13 @@ #include <mbgl/tile/geometry_tile.hpp> #include <mbgl/text/collision_tile.hpp> #include <mbgl/layout/symbol_layout.hpp> -#include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/renderer/bucket_parameters.hpp> #include <mbgl/renderer/group_by_layout.hpp> #include <mbgl/style/filter.hpp> #include <mbgl/style/filter_evaluator.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> -#include <mbgl/renderer/render_symbol_layer.hpp> -#include <mbgl/renderer/symbol_bucket.hpp> +#include <mbgl/renderer/layers/render_symbol_layer.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/string.hpp> @@ -26,16 +25,17 @@ GeometryTileWorker::GeometryTileWorker(ActorRef<GeometryTileWorker> self_, ActorRef<GeometryTile> parent_, OverscaledTileID id_, const std::atomic<bool>& obsolete_, - const MapMode mode_) + const MapMode mode_, + const float pixelRatio_) : self(std::move(self_)), parent(std::move(parent_)), id(std::move(id_)), obsolete(obsolete_), - mode(mode_) { + mode(mode_), + pixelRatio(pixelRatio_) { } -GeometryTileWorker::~GeometryTileWorker() { -} +GeometryTileWorker::~GeometryTileWorker() = default; /* GeometryTileWorker is a state machine. This is its transition diagram. @@ -92,7 +92,7 @@ void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_, } } -void GeometryTileWorker::setLayers(std::vector<std::unique_ptr<Layer>> layers_, uint64_t correlationID_) { +void GeometryTileWorker::setLayers(std::vector<Immutable<Layer::Impl>> layers_, uint64_t correlationID_) { try { layers = std::move(layers_); correlationID = correlationID_; @@ -144,14 +144,14 @@ void GeometryTileWorker::symbolDependenciesChanged() { try { switch (state) { case Idle: - if (hasPendingSymbolLayouts()) { + if (symbolLayoutsNeedPreparation) { attemptPlacement(); coalesce(); } break; case Coalescing: - if (hasPendingSymbolLayouts()) { + if (symbolLayoutsNeedPreparation) { state = NeedPlacement; } break; @@ -196,37 +196,40 @@ void GeometryTileWorker::coalesce() { self.invoke(&GeometryTileWorker::coalesced); } -void GeometryTileWorker::onGlyphsAvailable(GlyphPositionMap newGlyphPositions) { - for (auto& newFontGlyphs : newGlyphPositions) { +void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) { + for (auto& newFontGlyphs : newGlyphMap) { const FontStack& fontStack = newFontGlyphs.first; - GlyphPositions& newPositions = newFontGlyphs.second; + Glyphs& newGlyphs = newFontGlyphs.second; - GlyphPositions& positions = glyphPositions[fontStack]; + Glyphs& glyphs = glyphMap[fontStack]; GlyphIDs& pendingGlyphIDs = pendingGlyphDependencies[fontStack]; - for (auto& newPosition : newPositions) { - const GlyphID& glyphID = newPosition.first; - optional<Glyph>& glyph = newPosition.second; + for (auto& newGlyph : newGlyphs) { + const GlyphID& glyphID = newGlyph.first; + optional<Immutable<Glyph>>& glyph = newGlyph.second; if (pendingGlyphIDs.erase(glyphID)) { - positions.emplace(glyphID, std::move(glyph)); + glyphs.emplace(glyphID, std::move(glyph)); } } } symbolDependenciesChanged(); } -void GeometryTileWorker::onIconsAvailable(IconMap newIcons) { - icons = std::move(newIcons); - pendingIconDependencies.clear(); +void GeometryTileWorker::onImagesAvailable(ImageMap newImageMap, uint64_t imageCorrelationID_) { + if (imageCorrelationID != imageCorrelationID_) { + return; // Ignore outdated image request replies. + } + imageMap = std::move(newImageMap); + pendingImageDependencies.clear(); symbolDependenciesChanged(); } void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependencies) { for (auto& fontDependencies : glyphDependencies) { - auto fontGlyphs = glyphPositions.find(fontDependencies.first); + auto fontGlyphs = glyphMap.find(fontDependencies.first); for (auto glyphID : fontDependencies.second) { - if (fontGlyphs == glyphPositions.end() || fontGlyphs->second.find(glyphID) == fontGlyphs->second.end()) { + if (fontGlyphs == glyphMap.end() || fontGlyphs->second.find(glyphID) == fontGlyphs->second.end()) { pendingGlyphDependencies[fontDependencies.first].insert(glyphID); } } @@ -236,21 +239,20 @@ void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependen } } -void GeometryTileWorker::requestNewIcons(const IconDependencies& iconDependencies) { - pendingIconDependencies = iconDependencies; - if (!pendingIconDependencies.empty()) { - parent.invoke(&GeometryTile::getIcons, pendingIconDependencies); +void GeometryTileWorker::requestNewImages(const ImageDependencies& imageDependencies) { + pendingImageDependencies = imageDependencies; + if (!pendingImageDependencies.empty()) { + parent.invoke(&GeometryTile::getImages, std::make_pair(pendingImageDependencies, ++imageCorrelationID)); } } -static std::vector<std::unique_ptr<RenderLayer>> toRenderLayers(const std::vector<std::unique_ptr<style::Layer>>& layers, float zoom) { +static std::vector<std::unique_ptr<RenderLayer>> toRenderLayers(const std::vector<Immutable<style::Layer::Impl>>& layers, float zoom) { std::vector<std::unique_ptr<RenderLayer>> renderLayers; renderLayers.reserve(layers.size()); for (auto& layer : layers) { - renderLayers.push_back(layer->baseImpl->createRenderLayer()); + renderLayers.push_back(RenderLayer::create(layer)); - renderLayers.back()->cascade(CascadeParameters { - { ClassID::Default }, + renderLayers.back()->transition(TransitionParameters { Clock::time_point::max(), TransitionOptions() }); @@ -269,18 +271,18 @@ void GeometryTileWorker::redoLayout() { std::vector<std::string> symbolOrder; for (auto it = layers->rbegin(); it != layers->rend(); it++) { - if ((*it)->is<SymbolLayer>()) { - symbolOrder.push_back((*it)->getID()); + if ((*it)->type == LayerType::Symbol) { + symbolOrder.push_back((*it)->id); } } std::unordered_map<std::string, std::unique_ptr<SymbolLayout>> symbolLayoutMap; std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets; auto featureIndex = std::make_unique<FeatureIndex>(); - BucketParameters parameters { id, mode }; + BucketParameters parameters { id, mode, pixelRatio }; GlyphDependencies glyphDependencies; - IconDependencies iconDependencies; + ImageDependencies imageDependencies; // Create render layers and group by layout std::vector<std::unique_ptr<RenderLayer>> renderLayers = toRenderLayers(*layers, id.overscaledZ); @@ -297,7 +299,7 @@ void GeometryTileWorker::redoLayout() { const RenderLayer& leader = *group.at(0); - auto geometryLayer = (*data)->getLayer(leader.baseImpl.sourceLayer); + auto geometryLayer = (*data)->getLayer(leader.baseImpl->sourceLayer); if (!geometryLayer) { continue; } @@ -310,11 +312,13 @@ void GeometryTileWorker::redoLayout() { featureIndex->setBucketLayerIDs(leader.getID(), layerIDs); if (leader.is<RenderSymbolLayer>()) { - symbolLayoutMap.emplace(leader.getID(), - leader.as<RenderSymbolLayer>()->createLayout(parameters, group, *geometryLayer, glyphDependencies, iconDependencies)); + auto layout = leader.as<RenderSymbolLayer>()->createLayout( + parameters, group, std::move(geometryLayer), glyphDependencies, imageDependencies); + symbolLayoutMap.emplace(leader.getID(), std::move(layout)); + symbolLayoutsNeedPreparation = true; } else { - const Filter& filter = leader.baseImpl.filter; - const std::string& sourceLayerID = leader.baseImpl.sourceLayer; + const Filter& filter = leader.baseImpl->filter; + const std::string& sourceLayerID = leader.baseImpl->sourceLayer; std::shared_ptr<Bucket> bucket = leader.createBucket(parameters, group); for (std::size_t i = 0; !obsolete && i < geometryLayer->featureCount(); i++) { @@ -347,7 +351,7 @@ void GeometryTileWorker::redoLayout() { } requestNewGlyphs(glyphDependencies); - requestNewIcons(iconDependencies); + requestNewImages(imageDependencies); parent.invoke(&GeometryTile::onLayout, GeometryTile::LayoutResult { std::move(buckets), @@ -358,31 +362,42 @@ void GeometryTileWorker::redoLayout() { attemptPlacement(); } -bool GeometryTileWorker::hasPendingSymbolLayouts() const { - for (const auto& symbolLayout : symbolLayouts) { - if (symbolLayout->state == SymbolLayout::Pending) { - return true; - } - } - - return false; -} - bool GeometryTileWorker::hasPendingSymbolDependencies() const { for (auto& glyphDependency : pendingGlyphDependencies) { if (!glyphDependency.second.empty()) { return true; } } - return !pendingIconDependencies.empty(); + return !pendingImageDependencies.empty(); } - void GeometryTileWorker::attemptPlacement() { if (!data || !layers || !placementConfig || hasPendingSymbolDependencies()) { return; } + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; + + if (symbolLayoutsNeedPreparation) { + GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap); + ImageAtlas imageAtlas = makeImageAtlas(imageMap); + + glyphAtlasImage = std::move(glyphAtlas.image); + iconAtlasImage = std::move(imageAtlas.image); + + for (auto& symbolLayout : symbolLayouts) { + if (obsolete) { + return; + } + + symbolLayout->prepare(glyphMap, glyphAtlas.positions, + imageMap, imageAtlas.positions); + } + + symbolLayoutsNeedPreparation = false; + } + auto collisionTile = std::make_unique<CollisionTile>(*placementConfig); std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets; @@ -391,11 +406,6 @@ void GeometryTileWorker::attemptPlacement() { return; } - if (symbolLayout->state == SymbolLayout::Pending) { - symbolLayout->prepare(glyphPositions, icons); - symbolLayout->state = SymbolLayout::Placed; - } - if (!symbolLayout->hasSymbolInstances()) { continue; } @@ -408,7 +418,9 @@ void GeometryTileWorker::attemptPlacement() { parent.invoke(&GeometryTile::onPlacement, GeometryTile::PlacementResult { std::move(buckets), - std::move(collisionTile), + std::move(collisionTile), + std::move(glyphAtlasImage), + std::move(iconAtlasImage), }, correlationID); } diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp index 1df1ef43c4..1425daa7a1 100644 --- a/src/mbgl/tile/geometry_tile_worker.hpp +++ b/src/mbgl/tile/geometry_tile_worker.hpp @@ -2,11 +2,13 @@ #include <mbgl/map/mode.hpp> #include <mbgl/tile/tile_id.hpp> -#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/style/image_impl.hpp> #include <mbgl/text/glyph.hpp> #include <mbgl/text/placement_config.hpp> #include <mbgl/actor/actor_ref.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/util/immutable.hpp> +#include <mbgl/style/layer_impl.hpp> #include <atomic> #include <memory> @@ -15,9 +17,7 @@ namespace mbgl { class GeometryTile; class GeometryTileData; -class GlyphAtlas; class SymbolLayout; -class RenderLayer; namespace style { class Layer; @@ -29,15 +29,16 @@ public: ActorRef<GeometryTile> parent, OverscaledTileID, const std::atomic<bool>&, - const MapMode); + const MapMode, + const float pixelRatio); ~GeometryTileWorker(); - void setLayers(std::vector<std::unique_ptr<style::Layer>>, uint64_t correlationID); + void setLayers(std::vector<Immutable<style::Layer::Impl>>, uint64_t correlationID); void setData(std::unique_ptr<const GeometryTileData>, uint64_t correlationID); void setPlacementConfig(PlacementConfig, uint64_t correlationID); - void onGlyphsAvailable(GlyphPositionMap glyphs); - void onIconsAvailable(IconMap icons); + void onGlyphsAvailable(GlyphMap glyphs); + void onImagesAvailable(ImageMap images, uint64_t imageCorrelationID); private: void coalesced(); @@ -47,11 +48,10 @@ private: void coalesce(); void requestNewGlyphs(const GlyphDependencies&); - void requestNewIcons(const IconDependencies&); + void requestNewImages(const ImageDependencies&); void symbolDependenciesChanged(); bool hasPendingSymbolDependencies() const; - bool hasPendingSymbolLayouts() const; ActorRef<GeometryTileWorker> self; ActorRef<GeometryTile> parent; @@ -59,6 +59,7 @@ private: const OverscaledTileID id; const std::atomic<bool>& obsolete; const MapMode mode; + const float pixelRatio; enum State { Idle, @@ -69,17 +70,19 @@ private: State state = Idle; uint64_t correlationID = 0; + uint64_t imageCorrelationID = 0; // Outer optional indicates whether we've received it or not. - optional<std::vector<std::unique_ptr<style::Layer>>> layers; + optional<std::vector<Immutable<style::Layer::Impl>>> layers; optional<std::unique_ptr<const GeometryTileData>> data; optional<PlacementConfig> placementConfig; + bool symbolLayoutsNeedPreparation = false; std::vector<std::unique_ptr<SymbolLayout>> symbolLayouts; GlyphDependencies pendingGlyphDependencies; - IconDependencies pendingIconDependencies; - GlyphPositionMap glyphPositions; - IconMap icons; + ImageDependencies pendingImageDependencies; + GlyphMap glyphMap; + ImageMap imageMap; }; } // namespace mbgl diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp index 12dfaf87d4..2a3c9eeb0e 100644 --- a/src/mbgl/tile/raster_tile.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -7,8 +7,8 @@ #include <mbgl/storage/response.hpp> #include <mbgl/storage/file_source.hpp> #include <mbgl/renderer/tile_parameters.hpp> -#include <mbgl/renderer/raster_bucket.hpp> -#include <mbgl/util/run_loop.hpp> +#include <mbgl/renderer/buckets/raster_bucket.hpp> +#include <mbgl/actor/scheduler.hpp> namespace mbgl { @@ -17,7 +17,7 @@ RasterTile::RasterTile(const OverscaledTileID& id_, const Tileset& tileset) : Tile(id_), loader(*this, id_, parameters, tileset), - mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())), + mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())), worker(parameters.workerScheduler, ActorRef<RasterTile>(*this, mailbox)) { } @@ -43,7 +43,7 @@ void RasterTile::setData(std::shared_ptr<const std::string> data, worker.invoke(&RasterTileWorker::parse, data, correlationID); } -void RasterTile::onParsed(std::unique_ptr<Bucket> result, const uint64_t resultCorrelationID) { +void RasterTile::onParsed(std::unique_ptr<RasterBucket> result, const uint64_t resultCorrelationID) { bucket = std::move(result); loaded = true; if (resultCorrelationID == correlationID) { @@ -61,10 +61,22 @@ void RasterTile::onError(std::exception_ptr err, const uint64_t resultCorrelatio observer->onTileError(*this, err); } -Bucket* RasterTile::getBucket(const RenderLayer&) const { +void RasterTile::upload(gl::Context& context) { + if (bucket) { + bucket->upload(context); + } +} + +Bucket* RasterTile::getBucket(const style::Layer::Impl&) const { return bucket.get(); } +void RasterTile::setMask(TileMask&& mask) { + if (bucket) { + bucket->setMask(std::move(mask)); + } +} + void RasterTile::setNecessity(Necessity necessity) { loader.setNecessity(necessity); } diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp index 28fcb554a9..2cb64e8ed7 100644 --- a/src/mbgl/tile/raster_tile.hpp +++ b/src/mbgl/tile/raster_tile.hpp @@ -9,6 +9,7 @@ namespace mbgl { class Tileset; class TileParameters; +class RasterBucket; namespace style { class Layer; @@ -29,9 +30,13 @@ public: optional<Timestamp> expires_); void cancel() override; - Bucket* getBucket(const RenderLayer&) const override; - void onParsed(std::unique_ptr<Bucket> result, uint64_t correlationID); + void upload(gl::Context&) override; + Bucket* getBucket(const style::Layer::Impl&) const override; + + void setMask(TileMask&&) override; + + void onParsed(std::unique_ptr<RasterBucket> result, uint64_t correlationID); void onError(std::exception_ptr, uint64_t correlationID); private: @@ -44,7 +49,7 @@ private: // Contains the Bucket object for the tile. Buckets are render // objects and they get added by tile parsing operations. - std::unique_ptr<Bucket> bucket; + std::unique_ptr<RasterBucket> bucket; }; } // namespace mbgl diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp index 585fe5ec95..4afa876429 100644 --- a/src/mbgl/tile/raster_tile_worker.cpp +++ b/src/mbgl/tile/raster_tile_worker.cpp @@ -1,6 +1,6 @@ #include <mbgl/tile/raster_tile_worker.hpp> #include <mbgl/tile/raster_tile.hpp> -#include <mbgl/renderer/raster_bucket.hpp> +#include <mbgl/renderer/buckets/raster_bucket.hpp> #include <mbgl/actor/actor.hpp> #include <mbgl/util/premultiply.hpp> @@ -17,7 +17,7 @@ void RasterTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t c } try { - auto bucket = std::make_unique<RasterBucket>(util::unpremultiply(decodeImage(*data))); + auto bucket = std::make_unique<RasterBucket>(decodeImage(*data)); parent.invoke(&RasterTile::onParsed, std::move(bucket), correlationID); } catch (...) { parent.invoke(&RasterTile::onError, std::current_exception(), correlationID); diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index 0adc151a64..7d7eb0b3fc 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -1,9 +1,9 @@ #include <mbgl/tile/tile.hpp> #include <mbgl/tile/tile_observer.hpp> -#include <mbgl/renderer/debug_bucket.hpp> +#include <mbgl/renderer/buckets/debug_bucket.hpp> +#include <mbgl/renderer/query.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/logging.hpp> -#include <mbgl/map/query.hpp> namespace mbgl { @@ -33,6 +33,7 @@ void Tile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>&, const GeometryCoordinates&, const TransformState&, + const std::vector<const RenderLayer*>&, const RenderedQueryOptions&) {} void Tile::querySourceFeatures( diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index 795fd62140..39cc0de8bd 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -6,9 +6,11 @@ #include <mbgl/util/feature.hpp> #include <mbgl/util/tile_coordinate.hpp> #include <mbgl/tile/tile_id.hpp> +#include <mbgl/renderer/tile_mask.hpp> #include <mbgl/renderer/bucket.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/storage/resource.hpp> +#include <mbgl/style/layer_impl.hpp> #include <string> #include <memory> @@ -21,12 +23,13 @@ class DebugBucket; class TransformState; class TileObserver; class PlacementConfig; +class RenderLayer; class RenderedQueryOptions; class SourceQueryOptions; -class RenderLayer; -namespace style { -} // namespace style +namespace gl { +class Context; +} // namespace gl class Tile : private util::noncopyable { public: @@ -47,15 +50,18 @@ public: // Mark this tile as no longer needed and cancel any pending work. virtual void cancel() = 0; - virtual Bucket* getBucket(const RenderLayer&) const = 0; + virtual void upload(gl::Context&) = 0; + virtual Bucket* getBucket(const style::Layer::Impl&) const = 0; virtual void setPlacementConfig(const PlacementConfig&) {} - virtual void redoLayout() {} + virtual void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) {} + virtual void setMask(TileMask&&) {} virtual void queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, + const std::vector<const RenderLayer*>&, const RenderedQueryOptions& options); virtual void querySourceFeatures( @@ -101,6 +107,8 @@ public: // Contains the tile ID string for painting debug information. std::unique_ptr<DebugBucket> debugBucket; + + virtual float yStretch() const { return 1.0f; } protected: bool triedOptional = false; diff --git a/src/mbgl/tile/tile_id.hpp b/src/mbgl/tile/tile_id.hpp deleted file mode 100644 index 1ce3eea98e..0000000000 --- a/src/mbgl/tile/tile_id.hpp +++ /dev/null @@ -1,275 +0,0 @@ -#pragma once - -#include <mbgl/util/constants.hpp> - -#include <cstdint> -#include <array> -#include <forward_list> -#include <algorithm> -#include <iosfwd> -#include <cassert> -#include <boost/functional/hash.hpp> - -namespace mbgl { - -class OverscaledTileID; -class CanonicalTileID; -class UnwrappedTileID; - -// Has integer z/x/y coordinates -// All tiles must be derived from 0/0/0 (=no tiles outside of the main tile pyramid) -// Used for requesting data; represents data tiles that exist out there. -// z is never larger than the source's maxzoom -class CanonicalTileID { -public: - CanonicalTileID(uint8_t z, uint32_t x, uint32_t y); - bool operator==(const CanonicalTileID&) const; - bool operator!=(const CanonicalTileID&) const; - bool operator<(const CanonicalTileID&) const; - bool isChildOf(const CanonicalTileID&) const; - CanonicalTileID scaledTo(uint8_t z) const; - std::array<CanonicalTileID, 4> children() const; - - const uint8_t z; - const uint32_t x; - const uint32_t y; -}; - -::std::ostream& operator<<(::std::ostream& os, const CanonicalTileID& rhs); -namespace util { -std::string toString(const CanonicalTileID&); -} // namespace util - -// Has integer z/x/y coordinates -// overscaledZ describes the zoom level this tile is intented to represent, e.g. when parsing data -// z is never larger than the source's maxzoom -// z/x/y describe the -class OverscaledTileID { -public: - OverscaledTileID(uint8_t overscaledZ, CanonicalTileID); - OverscaledTileID(uint8_t overscaledZ, uint8_t z, uint32_t x, uint32_t y); - OverscaledTileID(uint8_t z, uint32_t x, uint32_t y); - explicit OverscaledTileID(const CanonicalTileID&); - explicit OverscaledTileID(CanonicalTileID&&); - bool operator==(const OverscaledTileID&) const; - bool operator!=(const OverscaledTileID&) const; - bool operator<(const OverscaledTileID&) const; - bool isChildOf(const OverscaledTileID&) const; - uint32_t overscaleFactor() const; - OverscaledTileID scaledTo(uint8_t z) const; - UnwrappedTileID unwrapTo(int16_t wrap) const; - - const uint8_t overscaledZ; - const CanonicalTileID canonical; -}; - -::std::ostream& operator<<(::std::ostream& os, const OverscaledTileID& rhs); -namespace util { -std::string toString(const OverscaledTileID&); -} // namespace util - -// Has integer z/x/y coordinates -// wrap describes tiles that are left/right of the main tile pyramid, e.g. when wrapping the world -// Used for describing what position tiles are getting rendered at (= calc the matrix) -// z is never larger than the source's maxzoom -class UnwrappedTileID { -public: - UnwrappedTileID(uint8_t z, int64_t x, int64_t y); - UnwrappedTileID(int16_t wrap, CanonicalTileID); - bool operator==(const UnwrappedTileID&) const; - bool operator!=(const UnwrappedTileID&) const; - bool operator<(const UnwrappedTileID&) const; - bool isChildOf(const UnwrappedTileID&) const; - std::array<UnwrappedTileID, 4> children() const; - OverscaledTileID overscaleTo(uint8_t z) const; - float pixelsToTileUnits(float pixelValue, float zoom) const; - - const int16_t wrap; - const CanonicalTileID canonical; -}; - -::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs); -namespace util { -std::string toString(const UnwrappedTileID&); -} // namespace util - -inline CanonicalTileID::CanonicalTileID(uint8_t z_, uint32_t x_, uint32_t y_) : z(z_), x(x_), y(y_) { - assert(z <= 32); - assert(x < (1ull << z)); - assert(y < (1ull << z)); -} - -inline bool CanonicalTileID::operator==(const CanonicalTileID& rhs) const { - return z == rhs.z && x == rhs.x && y == rhs.y; -} - -inline bool CanonicalTileID::operator!=(const CanonicalTileID& rhs) const { - return z != rhs.z || x != rhs.x || y != rhs.y; -} - -inline bool CanonicalTileID::operator<(const CanonicalTileID& rhs) const { - return std::tie(z, x, y) < std::tie(rhs.z, rhs.x, rhs.y); -} - -inline bool CanonicalTileID::isChildOf(const CanonicalTileID& parent) const { - // We're first testing for z == 0, to avoid a 32 bit shift, which is undefined. - return parent.z == 0 || - (parent.z < z && parent.x == (x >> (z - parent.z)) && parent.y == (y >> (z - parent.z))); -} - -inline CanonicalTileID CanonicalTileID::scaledTo(uint8_t targetZ) const { - if (targetZ <= z) { - return { targetZ, x >> (z - targetZ), y >> (z - targetZ) }; // parent or same - } else { - return { targetZ, x << (targetZ - z), y << (targetZ - z) }; // child - } -} - -inline std::array<CanonicalTileID, 4> CanonicalTileID::children() const { - const uint8_t childZ = z + 1; - const uint32_t childX = x * 2; - const uint32_t childY = y * 2; - return { { - { childZ, childX, childY }, - { childZ, childX, childY + 1 }, - { childZ, childX + 1, childY }, - { childZ, childX + 1, childY + 1 }, - } }; -} - -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, CanonicalTileID canonical_) - : overscaledZ(overscaledZ_), canonical(std::move(canonical_)) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(overscaledZ_), canonical(z, x, y) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(z), canonical(z, x, y) { -} - -inline OverscaledTileID::OverscaledTileID(const CanonicalTileID& canonical_) - : overscaledZ(canonical_.z), canonical(canonical_) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(CanonicalTileID&& canonical_) - : overscaledZ(canonical_.z), canonical(std::forward<CanonicalTileID>(canonical_)) { - assert(overscaledZ >= canonical.z); -} - -inline bool OverscaledTileID::operator==(const OverscaledTileID& rhs) const { - return overscaledZ == rhs.overscaledZ && canonical == rhs.canonical; -} - -inline bool OverscaledTileID::operator!=(const OverscaledTileID& rhs) const { - return overscaledZ != rhs.overscaledZ || canonical != rhs.canonical; -} - -inline bool OverscaledTileID::operator<(const OverscaledTileID& rhs) const { - return std::tie(overscaledZ, canonical) < std::tie(rhs.overscaledZ, rhs.canonical); -} - -inline uint32_t OverscaledTileID::overscaleFactor() const { - return 1u << (overscaledZ - canonical.z); -} - -inline bool OverscaledTileID::isChildOf(const OverscaledTileID& rhs) const { - return overscaledZ > rhs.overscaledZ && - (canonical == rhs.canonical || canonical.isChildOf(rhs.canonical)); -} - -inline OverscaledTileID OverscaledTileID::scaledTo(uint8_t z) const { - return { z, z >= canonical.z ? canonical : canonical.scaledTo(z) }; -} - -inline UnwrappedTileID OverscaledTileID::unwrapTo(int16_t wrap) const { - return { wrap, canonical }; -} - -inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_) - : wrap((x_ < 0 ? x_ - (1ll << z_) + 1 : x_) / (1ll << z_)), - canonical( - z_, - static_cast<uint32_t>(x_ - wrap * (1ll << z_)), - y_ < 0 ? 0 : std::min(static_cast<uint32_t>(y_), static_cast<uint32_t>(1ull << z_) - 1)) { -} - -inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, CanonicalTileID canonical_) - : wrap(wrap_), canonical(std::move(canonical_)) { -} - -inline bool UnwrappedTileID::operator==(const UnwrappedTileID& rhs) const { - return wrap == rhs.wrap && canonical == rhs.canonical; -} - -inline bool UnwrappedTileID::operator!=(const UnwrappedTileID& rhs) const { - return wrap != rhs.wrap || canonical != rhs.canonical; -} - -inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const { - return std::tie(wrap, canonical) < std::tie(rhs.wrap, rhs.canonical); -} - -inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const { - return wrap == parent.wrap && canonical.isChildOf(parent.canonical); -} - -inline std::array<UnwrappedTileID, 4> UnwrappedTileID::children() const { - const uint8_t childZ = canonical.z + 1; - const uint32_t childX = canonical.x * 2; - const uint32_t childY = canonical.y * 2; - return { { - { wrap, { childZ, childX, childY } }, - { wrap, { childZ, childX, childY + 1 } }, - { wrap, { childZ, childX + 1, childY } }, - { wrap, { childZ, childX + 1, childY + 1 } }, - } }; -} - -inline OverscaledTileID UnwrappedTileID::overscaleTo(const uint8_t overscaledZ) const { - assert(overscaledZ >= canonical.z); - return { overscaledZ, canonical }; -} - -inline float UnwrappedTileID::pixelsToTileUnits(const float pixelValue, const float zoom) const { - return pixelValue * (util::EXTENT / (util::tileSize * std::pow(2, zoom - canonical.z))); -} - -} // namespace mbgl - -namespace std { - -template <> struct hash<mbgl::CanonicalTileID> { - size_t operator()(const mbgl::CanonicalTileID &id) const { - std::size_t seed = 0; - boost::hash_combine(seed, id.x); - boost::hash_combine(seed, id.y); - boost::hash_combine(seed, id.z); - return seed; - } -}; - -template <> struct hash<mbgl::UnwrappedTileID> { - size_t operator()(const mbgl::UnwrappedTileID &id) const { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical)); - boost::hash_combine(seed, id.wrap); - return seed; - } -}; - -template <> struct hash<mbgl::OverscaledTileID> { - size_t operator()(const mbgl::OverscaledTileID &id) const { - std::size_t seed = 0; - boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical)); - boost::hash_combine(seed, id.overscaledZ); - return seed; - } -}; - -} // namespace std - diff --git a/src/mbgl/tile/tile_id_hash.cpp b/src/mbgl/tile/tile_id_hash.cpp new file mode 100644 index 0000000000..4a1f185817 --- /dev/null +++ b/src/mbgl/tile/tile_id_hash.cpp @@ -0,0 +1,29 @@ +#include <mbgl/tile/tile_id.hpp> + +#include <boost/functional/hash.hpp> + +namespace std { + +size_t hash<mbgl::CanonicalTileID>::operator()(const mbgl::CanonicalTileID& id) const { + std::size_t seed = 0; + boost::hash_combine(seed, id.x); + boost::hash_combine(seed, id.y); + boost::hash_combine(seed, id.z); + return seed; +} + +size_t hash<mbgl::UnwrappedTileID>::operator()(const mbgl::UnwrappedTileID& id) const { + std::size_t seed = 0; + boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical)); + boost::hash_combine(seed, id.wrap); + return seed; +} + +size_t hash<mbgl::OverscaledTileID>::operator()(const mbgl::OverscaledTileID& id) const { + std::size_t seed = 0; + boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical)); + boost::hash_combine(seed, id.overscaledZ); + return seed; +} + +} // namespace std diff --git a/src/mbgl/tile/tile_id_io.cpp b/src/mbgl/tile/tile_id_io.cpp index f6adbf183f..d8be6b93d6 100644 --- a/src/mbgl/tile/tile_id_io.cpp +++ b/src/mbgl/tile/tile_id_io.cpp @@ -6,6 +6,8 @@ namespace mbgl { ::std::ostream& operator<<(::std::ostream& os, const CanonicalTileID& rhs) { + // Uncomment this to create code instead of shorthands. + // return os << "CanonicalTileID{ " << uint32_t(rhs.z) << ", " << rhs.x << ", " << rhs.y << " }"; return os << uint32_t(rhs.z) << "/" << rhs.x << "/" << rhs.y; } @@ -26,6 +28,9 @@ std::string toString(const OverscaledTileID& rhs) { } // namespace util ::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs) { + // Uncomment this to create code instead of shorthands. + // return os << "UnwrappedTileID{ " << uint32_t(rhs.wrap) << ", { " << uint32_t(rhs.canonical.z) + // << ", " << rhs.canonical.x << ", " << rhs.canonical.y << " } }"; return os << rhs.canonical << (rhs.wrap >= 0 ? "+" : "") << rhs.wrap; } diff --git a/src/mbgl/tile/tile_loader_impl.hpp b/src/mbgl/tile/tile_loader_impl.hpp index 899cbaf9b0..598ec32c10 100644 --- a/src/mbgl/tile/tile_loader_impl.hpp +++ b/src/mbgl/tile/tile_loader_impl.hpp @@ -61,7 +61,10 @@ void TileLoader<T>::loadOptional() { // When the optional request could not be satisfied, don't treat it as an error. // Instead, we make sure that the next request knows that there has been an optional // request before by setting one of the prior* fields. + resource.priorModified = res.modified; resource.priorExpires = Timestamp{ Seconds::zero() }; + resource.priorEtag = res.etag; + resource.priorData = res.data; } else { loadedData(res); } diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp index 46914e5f5a..e2e700b7b7 100644 --- a/src/mbgl/tile/vector_tile.cpp +++ b/src/mbgl/tile/vector_tile.cpp @@ -1,94 +1,15 @@ #include <mbgl/tile/vector_tile.hpp> +#include <mbgl/tile/vector_tile_data.hpp> #include <mbgl/tile/tile_loader_impl.hpp> -#include <mbgl/tile/geometry_tile_data.hpp> -#include <mbgl/style/style.hpp> #include <mbgl/renderer/tile_parameters.hpp> -#include <protozero/pbf_reader.hpp> - -#include <unordered_map> -#include <functional> -#include <utility> - namespace mbgl { -class VectorTileLayer; - -using packed_iter_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>; - -struct VectorTileLayerData { - VectorTileLayerData(std::shared_ptr<const std::string>); - - // Hold a reference to the underlying pbf data that backs the lazily-built - // components of the owning VectorTileLayer and VectorTileFeature objects - std::shared_ptr<const std::string> data; - - uint32_t version = 1; - uint32_t extent = 4096; - std::unordered_map<std::string, uint32_t> keysMap; - std::vector<std::reference_wrapper<const std::string>> keys; - std::vector<Value> values; -}; - -class VectorTileFeature : public GeometryTileFeature { -public: - VectorTileFeature(protozero::pbf_reader, std::shared_ptr<VectorTileLayerData> layerData); - - FeatureType getType() const override { return type; } - optional<Value> getValue(const std::string&) const override; - std::unordered_map<std::string,Value> getProperties() const override; - optional<FeatureIdentifier> getID() const override; - GeometryCollection getGeometries() const override; - -private: - std::shared_ptr<VectorTileLayerData> layerData; - optional<FeatureIdentifier> id; - FeatureType type = FeatureType::Unknown; - packed_iter_type tags_iter; - packed_iter_type geometry_iter; -}; - -class VectorTileLayer : public GeometryTileLayer { -public: - VectorTileLayer(protozero::pbf_reader, std::shared_ptr<const std::string>); - - std::size_t featureCount() const override { return features.size(); } - std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const override; - std::string getName() const override; - -private: - friend class VectorTileData; - friend class VectorTileFeature; - - std::string name; - std::vector<protozero::pbf_reader> features; - std::shared_ptr<VectorTileLayerData> data; -}; - -class VectorTileData : public GeometryTileData { -public: - VectorTileData(std::shared_ptr<const std::string> data); - - std::unique_ptr<GeometryTileData> clone() const override { - return std::make_unique<VectorTileData>(*this); - } - - const GeometryTileLayer* getLayer(const std::string&) const override; - -private: - std::shared_ptr<const std::string> data; - mutable bool parsed = false; - mutable std::unordered_map<std::string, VectorTileLayer> layers; -}; - VectorTile::VectorTile(const OverscaledTileID& id_, std::string sourceID_, const TileParameters& parameters, const Tileset& tileset) - : GeometryTile(id_, sourceID_, parameters, - *parameters.style.glyphAtlas, - *parameters.style.spriteAtlas), - loader(*this, id_, parameters, tileset) { + : GeometryTile(id_, sourceID_, parameters), loader(*this, id_, parameters, tileset) { } void VectorTile::setNecessity(Necessity necessity) { @@ -104,220 +25,4 @@ void VectorTile::setData(std::shared_ptr<const std::string> data_, GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr); } -Value parseValue(protozero::pbf_reader data) { - while (data.next()) - { - switch (data.tag()) { - case 1: // string_value - return data.get_string(); - case 2: // float_value - return static_cast<double>(data.get_float()); - case 3: // double_value - return data.get_double(); - case 4: // int_value - return data.get_int64(); - case 5: // uint_value - return data.get_uint64(); - case 6: // sint_value - return data.get_sint64(); - case 7: // bool_value - return data.get_bool(); - default: - data.skip(); - break; - } - } - return false; -} - -VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, std::shared_ptr<VectorTileLayerData> layerData_) - : layerData(std::move(layerData_)) { - while (feature_pbf.next()) { - switch (feature_pbf.tag()) { - case 1: // id - id = { feature_pbf.get_uint64() }; - break; - case 2: // tags - tags_iter = feature_pbf.get_packed_uint32(); - break; - case 3: // type - type = static_cast<FeatureType>(feature_pbf.get_enum()); - break; - case 4: // geometry - geometry_iter = feature_pbf.get_packed_uint32(); - break; - default: - feature_pbf.skip(); - break; - } - } -} - -optional<Value> VectorTileFeature::getValue(const std::string& key) const { - auto keyIter = layerData->keysMap.find(key); - if (keyIter == layerData->keysMap.end()) { - return optional<Value>(); - } - - auto start_itr = tags_iter.begin(); - const auto & end_itr = tags_iter.end(); - while (start_itr != end_itr) { - uint32_t tag_key = static_cast<uint32_t>(*start_itr++); - - if (layerData->keysMap.size() <= tag_key) { - throw std::runtime_error("feature referenced out of range key"); - } - - if (start_itr == end_itr) { - throw std::runtime_error("uneven number of feature tag ids"); - } - - uint32_t tag_val = static_cast<uint32_t>(*start_itr++);; - if (layerData->values.size() <= tag_val) { - throw std::runtime_error("feature referenced out of range value"); - } - - if (tag_key == keyIter->second) { - return layerData->values[tag_val]; - } - } - - return optional<Value>(); -} - -std::unordered_map<std::string,Value> VectorTileFeature::getProperties() const { - std::unordered_map<std::string,Value> properties; - auto start_itr = tags_iter.begin(); - const auto & end_itr = tags_iter.end(); - while (start_itr != end_itr) { - uint32_t tag_key = static_cast<uint32_t>(*start_itr++); - if (start_itr == end_itr) { - throw std::runtime_error("uneven number of feature tag ids"); - } - uint32_t tag_val = static_cast<uint32_t>(*start_itr++); - properties[layerData->keys.at(tag_key)] = layerData->values.at(tag_val); - } - return properties; -} - -optional<FeatureIdentifier> VectorTileFeature::getID() const { - return id; -} - -GeometryCollection VectorTileFeature::getGeometries() const { - uint8_t cmd = 1; - uint32_t length = 0; - int32_t x = 0; - int32_t y = 0; - const float scale = float(util::EXTENT) / layerData->extent; - - GeometryCollection lines; - - lines.emplace_back(); - GeometryCoordinates* line = &lines.back(); - - auto g_itr = geometry_iter.begin(); - while (g_itr != geometry_iter.end()) { - if (length == 0) { - uint32_t cmd_length = static_cast<uint32_t>(*g_itr++); - cmd = cmd_length & 0x7; - length = cmd_length >> 3; - } - - --length; - - if (cmd == 1 || cmd == 2) { - x += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); - y += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); - - if (cmd == 1 && !line->empty()) { // moveTo - lines.emplace_back(); - line = &lines.back(); - } - - line->emplace_back(::round(x * scale), ::round(y * scale)); - - } else if (cmd == 7) { // closePolygon - if (!line->empty()) { - line->push_back((*line)[0]); - } - - } else { - throw std::runtime_error("unknown command"); - } - } - - if (layerData->version >= 2 || type != FeatureType::Polygon) { - return lines; - } - - return fixupPolygons(lines); -} - -VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_) - : data(std::move(data_)) { -} - -const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const { - if (!parsed) { - parsed = true; - protozero::pbf_reader tile_pbf(*data); - while (tile_pbf.next(3)) { - VectorTileLayer layer(tile_pbf.get_message(), data); - layers.emplace(layer.name, std::move(layer)); - } - } - - auto it = layers.find(name); - if (it != layers.end()) { - return &it->second; - } - return nullptr; -} - -VectorTileLayerData::VectorTileLayerData(std::shared_ptr<const std::string> pbfData) : - data(std::move(pbfData)) -{} - -VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf, std::shared_ptr<const std::string> pbfData) - : data(std::make_shared<VectorTileLayerData>(std::move(pbfData))) -{ - while (layer_pbf.next()) { - switch (layer_pbf.tag()) { - case 1: // name - name = layer_pbf.get_string(); - break; - case 2: // feature - features.push_back(layer_pbf.get_message()); - break; - case 3: // keys - { - auto iter = data->keysMap.emplace(layer_pbf.get_string(), data->keysMap.size()); - data->keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first)); - } - break; - case 4: // values - data->values.emplace_back(parseValue(layer_pbf.get_message())); - break; - case 5: // extent - data->extent = layer_pbf.get_uint32(); - break; - case 15: // version - data->version = layer_pbf.get_uint32(); - break; - default: - layer_pbf.skip(); - break; - } - } -} - -std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const { - return std::make_unique<VectorTileFeature>(features.at(i), data); -} - -std::string VectorTileLayer::getName() const { - return name; -} - } // namespace mbgl diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp new file mode 100644 index 0000000000..2d4a01bda3 --- /dev/null +++ b/src/mbgl/tile/vector_tile_data.cpp @@ -0,0 +1,89 @@ +#include <mbgl/tile/vector_tile_data.hpp> +#include <mbgl/util/constants.hpp> + +namespace mbgl { + +VectorTileFeature::VectorTileFeature(const mapbox::vector_tile::layer& layer, + const protozero::data_view& view) + : feature(view, layer) { +} + +FeatureType VectorTileFeature::getType() const { + switch (feature.getType()) { + case mapbox::vector_tile::GeomType::POINT: + return FeatureType::Point; + case mapbox::vector_tile::GeomType::LINESTRING: + return FeatureType::LineString; + case mapbox::vector_tile::GeomType::POLYGON: + return FeatureType::Polygon; + default: + return FeatureType::Unknown; + } +} + +optional<Value> VectorTileFeature::getValue(const std::string& key) const { + return feature.getValue(key); +} + +std::unordered_map<std::string, Value> VectorTileFeature::getProperties() const { + return feature.getProperties(); +} + +optional<FeatureIdentifier> VectorTileFeature::getID() const { + return feature.getID(); +} + +GeometryCollection VectorTileFeature::getGeometries() const { + const float scale = float(util::EXTENT) / feature.getExtent(); + auto lines = feature.getGeometries<GeometryCollection>(scale); + if (feature.getVersion() >= 2 || feature.getType() != mapbox::vector_tile::GeomType::POLYGON) { + return lines; + } else { + return fixupPolygons(lines); + } +} + +VectorTileLayer::VectorTileLayer(std::shared_ptr<const std::string> data_, + const protozero::data_view& view) + : data(std::move(data_)), layer(view) { +} + +std::size_t VectorTileLayer::featureCount() const { + return layer.featureCount(); +} + +std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const { + return std::make_unique<VectorTileFeature>(layer, layer.getFeature(i)); +} + +std::string VectorTileLayer::getName() const { + return layer.getName(); +} + +VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_) : data(std::move(data_)) { +} + +std::unique_ptr<GeometryTileData> VectorTileData::clone() const { + return std::make_unique<VectorTileData>(data); +} + +std::unique_ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const { + if (!parsed) { + // We're parsing this lazily so that we can construct VectorTileData objects on the main + // thread without incurring the overhead of parsing immediately. + layers = mapbox::vector_tile::buffer(*data).getLayers(); + parsed = true; + } + + auto it = layers.find(name); + if (it != layers.end()) { + return std::make_unique<VectorTileLayer>(data, it->second); + } + return nullptr; +} + +std::vector<std::string> VectorTileData::layerNames() const { + return mapbox::vector_tile::buffer(*data).layerNames(); +} + +} // namespace mbgl diff --git a/src/mbgl/tile/vector_tile_data.hpp b/src/mbgl/tile/vector_tile_data.hpp new file mode 100644 index 0000000000..48beaf9d07 --- /dev/null +++ b/src/mbgl/tile/vector_tile_data.hpp @@ -0,0 +1,54 @@ +#include <mbgl/tile/geometry_tile_data.hpp> + +#include <mapbox/vector_tile.hpp> +#include <protozero/pbf_reader.hpp> + +#include <unordered_map> +#include <functional> +#include <utility> + +namespace mbgl { + +class VectorTileFeature : public GeometryTileFeature { +public: + VectorTileFeature(const mapbox::vector_tile::layer&, const protozero::data_view&); + + FeatureType getType() const override; + optional<Value> getValue(const std::string& key) const override; + std::unordered_map<std::string, Value> getProperties() const override; + optional<FeatureIdentifier> getID() const override; + GeometryCollection getGeometries() const override; + +private: + mapbox::vector_tile::feature feature; +}; + +class VectorTileLayer : public GeometryTileLayer { +public: + VectorTileLayer(std::shared_ptr<const std::string> data, const protozero::data_view&); + + std::size_t featureCount() const override; + std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override; + std::string getName() const override; + +private: + std::shared_ptr<const std::string> data; + mapbox::vector_tile::layer layer; +}; + +class VectorTileData : public GeometryTileData { +public: + VectorTileData(std::shared_ptr<const std::string> data); + + std::unique_ptr<GeometryTileData> clone() const override; + std::unique_ptr<GeometryTileLayer> getLayer(const std::string& name) const override; + + std::vector<std::string> layerNames() const; + +private: + std::shared_ptr<const std::string> data; + mutable bool parsed = false; + mutable std::map<std::string, const protozero::data_view> layers; +}; + +} // namespace mbgl |