diff options
Diffstat (limited to 'src/mbgl/tile')
-rw-r--r-- | src/mbgl/tile/geojson_tile.cpp | 47 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile.cpp | 114 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile.hpp | 49 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_data.hpp | 9 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_worker.cpp | 94 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_worker.hpp | 26 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile_worker.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/tile/tile.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/tile/tile.hpp | 14 | ||||
-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 |
14 files changed, 376 insertions, 438 deletions
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 3c4939a0a6..e9865e8272 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -1,7 +1,6 @@ #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/tile_parameters.hpp> #include <mapbox/geojsonvt.hpp> @@ -52,43 +51,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 29ba7d42cd..4ab11d79fe 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -6,11 +6,12 @@ #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/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> @@ -29,30 +30,32 @@ using namespace style; 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())), worker(parameters.workerScheduler, ActorRef<GeometryTile>(*this, mailbox), id_, obsolete, - parameters.mode), - glyphAtlas(glyphAtlas_), - spriteAtlas(spriteAtlas_), + parameters.mode, + parameters.pixelRatio), + glyphManager(parameters.glyphManager), + imageManager(parameters.imageManager), placementThrottler(Milliseconds(300), [this] { invokePlacement(); }) { } 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; } @@ -69,7 +72,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) { @@ -92,29 +94,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) { @@ -134,10 +136,13 @@ void GeometryTile::onPlacement(PlacementResult result) { 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); + } observer->onTileChanged(*this); } @@ -148,25 +153,51 @@ void GeometryTile::onError(std::exception_ptr err) { 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::onImagesAvailable(ImageMap images) { + worker.invoke(&GeometryTileWorker::onImagesAvailable, std::move(images)); } -void GeometryTile::onIconsAvailable(IconMap icons) { - worker.invoke(&GeometryTileWorker::onIconsAvailable, std::move(icons)); +void GeometryTile::getImages(ImageDependencies imageDependencies) { + imageManager.getImages(*this, std::move(imageDependencies)); } -void GeometryTile::getIcons(IconDependencies) { - spriteAtlas.getIcons(*this); +void GeometryTile::upload(gl::Context& context) { + auto upload = [&] (Bucket& bucket) { + if (bucket.needsUpload()) { + bucket.upload(context); + } + }; + + for (auto& entry : nonSymbolBuckets) { + upload(*entry.second); + } + + for (auto& entry : symbolBuckets) { + upload(*entry.second); + } + + if (glyphAtlasImage) { + glyphAtlasTexture = context.createTexture(*glyphAtlasImage, 0); + glyphAtlasImage = {}; + } + + if (iconAtlasImage) { + iconAtlasTexture = context.createTexture(*iconAtlasImage, 0); + iconAtlasImage = {}; + } } -Bucket* GeometryTile::getBucket(const RenderLayer& layer) const { - const auto& buckets = layer.is<RenderSymbolLayer>() ? symbolBuckets : nonSymbolBuckets; - const auto it = buckets.find(layer.baseImpl.id); +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; } @@ -179,6 +210,7 @@ void GeometryTile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState& transformState, + const RenderStyle& style, const RenderedQueryOptions& options) { if (!featureIndex || !data) return; diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index ed5d8d87bf..77202d20b6 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -1,9 +1,9 @@ #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/util/feature.hpp> #include <mbgl/util/throttler.hpp> @@ -19,21 +19,18 @@ namespace mbgl { class GeometryTileData; class FeatureIndex; class CollisionTile; +class RenderStyle; 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 +38,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) override; void getGlyphs(GlyphDependencies); - void getIcons(IconDependencies); + void getImages(ImageDependencies); + + 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 RenderStyle&, const RenderedQueryOptions& options) override; void querySourceFeatures( @@ -76,6 +78,8 @@ public: public: std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets; std::unique_ptr<CollisionTile> collisionTile; + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; uint64_t correlationID; }; void onPlacement(PlacementResult); @@ -88,10 +92,10 @@ protected: } 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 }; @@ -99,8 +103,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; @@ -109,10 +113,17 @@ 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; + +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 616a0bba1f..12bb84d7e3 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_; @@ -196,37 +196,37 @@ 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) { + 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 +236,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, pendingImageDependencies); } } -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 +268,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 +296,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 +309,12 @@ 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)); } 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 +347,7 @@ void GeometryTileWorker::redoLayout() { } requestNewGlyphs(glyphDependencies); - requestNewIcons(iconDependencies); + requestNewImages(imageDependencies); parent.invoke(&GeometryTile::onLayout, GeometryTile::LayoutResult { std::move(buckets), @@ -375,7 +375,7 @@ bool GeometryTileWorker::hasPendingSymbolDependencies() const { return true; } } - return !pendingIconDependencies.empty(); + return !pendingImageDependencies.empty(); } @@ -387,14 +387,24 @@ void GeometryTileWorker::attemptPlacement() { auto collisionTile = std::make_unique<CollisionTile>(*placementConfig); std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets; + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; + for (auto& symbolLayout : symbolLayouts) { if (obsolete) { return; } if (symbolLayout->state == SymbolLayout::Pending) { - symbolLayout->prepare(glyphPositions, icons); + GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap); + ImageAtlas imageAtlas = makeImageAtlas(imageMap); + + symbolLayout->prepare(glyphMap, glyphAtlas.positions, + imageMap, imageAtlas.positions); symbolLayout->state = SymbolLayout::Placed; + + glyphAtlasImage = std::move(glyphAtlas.image); + iconAtlasImage = std::move(imageAtlas.image); } if (!symbolLayout->hasSymbolInstances()) { @@ -410,6 +420,8 @@ void GeometryTileWorker::attemptPlacement() { parent.invoke(&GeometryTile::onPlacement, GeometryTile::PlacementResult { std::move(buckets), 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..194477e7b8 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); private: void coalesced(); @@ -47,7 +48,7 @@ private: void coalesce(); void requestNewGlyphs(const GlyphDependencies&); - void requestNewIcons(const IconDependencies&); + void requestNewImages(const ImageDependencies&); void symbolDependenciesChanged(); bool hasPendingSymbolDependencies() const; @@ -59,6 +60,7 @@ private: const OverscaledTileID id; const std::atomic<bool>& obsolete; const MapMode mode; + const float pixelRatio; enum State { Idle, @@ -71,15 +73,15 @@ private: uint64_t correlationID = 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; 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 b1a901e565..8a92c40e4a 100644 --- a/src/mbgl/tile/raster_tile.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -7,7 +7,7 @@ #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/renderer/buckets/raster_bucket.hpp> #include <mbgl/util/run_loop.hpp> namespace mbgl { @@ -55,7 +55,13 @@ void RasterTile::onError(std::exception_ptr err) { 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(); } diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp index e047430485..51075a2dbc 100644 --- a/src/mbgl/tile/raster_tile.hpp +++ b/src/mbgl/tile/raster_tile.hpp @@ -29,7 +29,9 @@ public: optional<Timestamp> expires_); void cancel() override; - Bucket* getBucket(const RenderLayer&) const override; + + void upload(gl::Context&) override; + Bucket* getBucket(const style::Layer::Impl&) const override; void onParsed(std::unique_ptr<Bucket> result); void onError(std::exception_ptr); diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp index 8c1fc2f673..86fb5f181d 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> diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index 0adc151a64..5080d42933 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -1,6 +1,6 @@ #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/util/string.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/map/query.hpp> @@ -33,6 +33,7 @@ void Tile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>&, const GeometryCoordinates&, const TransformState&, + const RenderStyle&, const RenderedQueryOptions&) {} void Tile::querySourceFeatures( diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index 795fd62140..a925d88af3 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -9,6 +9,7 @@ #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 +22,13 @@ class DebugBucket; class TransformState; class TileObserver; class PlacementConfig; +class RenderStyle; class RenderedQueryOptions; class SourceQueryOptions; -class RenderLayer; -namespace style { -} // namespace style +namespace gl { +class Context; +} // namespace gl class Tile : private util::noncopyable { public: @@ -47,15 +49,17 @@ 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 queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, + const RenderStyle&, const RenderedQueryOptions& options); virtual void querySourceFeatures( 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 |