From 4676553a3e31bef3094e8be5d6f9dce2809ef5ae Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 4 Jun 2015 19:32:07 -0700 Subject: [PATCH] Merge TileParser into TileWorker --- src/mbgl/map/tile_parser.cpp | 235 ----------------------------------- src/mbgl/map/tile_parser.hpp | 62 --------- src/mbgl/map/tile_worker.cpp | 218 ++++++++++++++++++++++++++++++-- src/mbgl/map/tile_worker.hpp | 24 +++- 4 files changed, 232 insertions(+), 307 deletions(-) delete mode 100644 src/mbgl/map/tile_parser.cpp delete mode 100644 src/mbgl/map/tile_parser.hpp diff --git a/src/mbgl/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp deleted file mode 100644 index a88084391..000000000 --- a/src/mbgl/map/tile_parser.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace mbgl { - -// Note: This destructor is seemingly empty, but we need to declare it anyway -// because this object has a std::unique_ptr<> of a forward-declare type in -// its header file. -TileParser::~TileParser() = default; - -TileParser::TileParser(const GeometryTile& geometryTile_, - TileWorker& tile_, - Style& style_) - : geometryTile(geometryTile_), - tile(tile_), - style(style_), - partialParse(false) { - assert(style.sprite); -} - -bool TileParser::obsolete() const { - return tile.getState() == TileData::State::obsolete; -} - -void TileParser::parse() { - for (const auto& layer_desc : style.layers) { - // Cancel early when parsing. - if (obsolete()) { - return; - } - - if (layer_desc->isBackground()) { - // background is a special, fake bucket - continue; - } - - if (layer_desc->bucket) { - // This is a singular layer. Check if this bucket already exists. If not, - // parse this bucket. - if (tile.getBucket(*layer_desc)) { - continue; - } - - std::unique_ptr bucket = createBucket(*layer_desc->bucket); - if (bucket) { - // Bucket creation might fail because the data tile may not - // contain any data that falls into this bucket. - tile.setBucket(*layer_desc, std::move(bucket)); - } - } else { - Log::Warning(Event::ParseTile, "layer '%s' does not have buckets", layer_desc->id.c_str()); - } - } -} - -template -struct PropertyEvaluator { - typedef T result_type; - PropertyEvaluator(float z_) : z(z_) {} - - template ::value, int>::type = 0> - T operator()(const P &value) const { - return value; - } - - T operator()(const Function &value) const { - return mapbox::util::apply_visitor(FunctionEvaluator(z), value); - } - - template ::value, int>::type = 0> - T operator()(const P &) const { - return T(); - } - -private: - const float z; -}; - -template -void applyLayoutProperty(PropertyKey key, const ClassProperties &classProperties, T &target, const float z) { - auto it = classProperties.properties.find(key); - if (it != classProperties.properties.end()) { - const PropertyEvaluator evaluator(z); - target = mapbox::util::apply_visitor(evaluator, it->second); - } -} - -std::unique_ptr TileParser::createBucket(const StyleBucket &bucketDesc) { - // Skip this bucket if we are to not render this - if (tile.id.z < std::floor(bucketDesc.min_zoom) && std::floor(bucketDesc.min_zoom) < tile.maxZoom) return nullptr; - if (tile.id.z >= std::ceil(bucketDesc.max_zoom)) return nullptr; - if (bucketDesc.visibility == mbgl::VisibilityType::None) return nullptr; - - auto layer = geometryTile.getLayer(bucketDesc.source_layer); - if (layer) { - if (bucketDesc.type == StyleLayerType::Fill) { - return createFillBucket(*layer, bucketDesc); - } else if (bucketDesc.type == StyleLayerType::Line) { - return createLineBucket(*layer, bucketDesc); - } else if (bucketDesc.type == StyleLayerType::Symbol) { - return createSymbolBucket(*layer, bucketDesc); - } else if (bucketDesc.type == StyleLayerType::Raster) { - return nullptr; - } else { - Log::Warning(Event::ParseTile, "unknown bucket render type for layer '%s' (source layer '%s')", - bucketDesc.name.c_str(), bucketDesc.source_layer.c_str()); - } - } else { - // The layer specified in the bucket does not exist. Do nothing. - if (debug::tileParseWarnings) { - Log::Warning(Event::ParseTile, "layer '%s' does not exist in tile %d/%d/%d", - bucketDesc.source_layer.c_str(), tile.id.z, tile.id.x, tile.id.y); - } - } - - return nullptr; -} - -template -void TileParser::addBucketGeometries(Bucket& bucket, const GeometryTileLayer& layer, const FilterExpression &filter) { - for (std::size_t i = 0; i < layer.featureCount(); i++) { - auto feature = layer.getFeature(i); - - if (obsolete()) - return; - - GeometryTileFeatureExtractor extractor(*feature); - if (!evaluate(filter, extractor)) - continue; - - bucket->addGeometry(feature->getGeometries()); - } -} - -std::unique_ptr TileParser::createFillBucket(const GeometryTileLayer& layer, - const StyleBucket& bucket_desc) { - auto bucket = std::make_unique(tile.fillVertexBuffer, - tile.triangleElementsBuffer, - tile.lineElementsBuffer); - addBucketGeometries(bucket, layer, bucket_desc.filter); - return bucket->hasData() ? std::move(bucket) : nullptr; -} - -std::unique_ptr TileParser::createLineBucket(const GeometryTileLayer& layer, - const StyleBucket& bucket_desc) { - auto bucket = std::make_unique(tile.lineVertexBuffer, - tile.triangleElementsBuffer); - - const float z = tile.id.z; - auto& layout = bucket->layout; - - applyLayoutProperty(PropertyKey::LineCap, bucket_desc.layout, layout.cap, z); - applyLayoutProperty(PropertyKey::LineJoin, bucket_desc.layout, layout.join, z); - applyLayoutProperty(PropertyKey::LineMiterLimit, bucket_desc.layout, layout.miter_limit, z); - applyLayoutProperty(PropertyKey::LineRoundLimit, bucket_desc.layout, layout.round_limit, z); - - addBucketGeometries(bucket, layer, bucket_desc.filter); - return bucket->hasData() ? std::move(bucket) : nullptr; -} - -std::unique_ptr TileParser::createSymbolBucket(const GeometryTileLayer& layer, - const StyleBucket& bucket_desc) { - auto bucket = std::make_unique(*tile.getCollision(), tile.id.overscaling); - - const float z = tile.id.z; - auto& layout = bucket->layout; - - applyLayoutProperty(PropertyKey::SymbolPlacement, bucket_desc.layout, layout.placement, z); - if (layout.placement == PlacementType::Line) { - layout.icon.rotation_alignment = RotationAlignmentType::Map; - layout.text.rotation_alignment = RotationAlignmentType::Map; - }; - applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, layout.min_distance, z); - applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, layout.avoid_edges, z); - - applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, layout.icon.allow_overlap, z); - applyLayoutProperty(PropertyKey::IconIgnorePlacement, bucket_desc.layout, layout.icon.ignore_placement, z); - applyLayoutProperty(PropertyKey::IconOptional, bucket_desc.layout, layout.icon.optional, z); - applyLayoutProperty(PropertyKey::IconRotationAlignment, bucket_desc.layout, layout.icon.rotation_alignment, z); - applyLayoutProperty(PropertyKey::IconMaxSize, bucket_desc.layout, layout.icon.max_size, z); - applyLayoutProperty(PropertyKey::IconImage, bucket_desc.layout, layout.icon.image, z); - applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, layout.icon.padding, z); - applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, layout.icon.rotate, z); - applyLayoutProperty(PropertyKey::IconKeepUpright, bucket_desc.layout, layout.icon.keep_upright, z); - applyLayoutProperty(PropertyKey::IconOffset, bucket_desc.layout, layout.icon.offset, z); - - applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, layout.text.rotation_alignment, z); - applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, layout.text.field, z); - applyLayoutProperty(PropertyKey::TextFont, bucket_desc.layout, layout.text.font, z); - applyLayoutProperty(PropertyKey::TextMaxSize, bucket_desc.layout, layout.text.max_size, z); - applyLayoutProperty(PropertyKey::TextMaxWidth, bucket_desc.layout, layout.text.max_width, z); - applyLayoutProperty(PropertyKey::TextLineHeight, bucket_desc.layout, layout.text.line_height, z); - applyLayoutProperty(PropertyKey::TextLetterSpacing, bucket_desc.layout, layout.text.letter_spacing, z); - applyLayoutProperty(PropertyKey::TextMaxAngle, bucket_desc.layout, layout.text.max_angle, z); - applyLayoutProperty(PropertyKey::TextRotate, bucket_desc.layout, layout.text.rotate, z); - applyLayoutProperty(PropertyKey::TextPadding, bucket_desc.layout, layout.text.padding, z); - applyLayoutProperty(PropertyKey::TextIgnorePlacement, bucket_desc.layout, layout.text.ignore_placement, z); - applyLayoutProperty(PropertyKey::TextOptional, bucket_desc.layout, layout.text.optional, z); - applyLayoutProperty(PropertyKey::TextJustify, bucket_desc.layout, layout.text.justify, z); - applyLayoutProperty(PropertyKey::TextAnchor, bucket_desc.layout, layout.text.anchor, z); - applyLayoutProperty(PropertyKey::TextKeepUpright, bucket_desc.layout, layout.text.keep_upright, z); - applyLayoutProperty(PropertyKey::TextTransform, bucket_desc.layout, layout.text.transform, z); - applyLayoutProperty(PropertyKey::TextOffset, bucket_desc.layout, layout.text.offset, z); - applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, layout.text.allow_overlap, z); - - if (bucket->needsDependencies(layer, bucket_desc.filter, *style.glyphStore, *style.sprite)) { - partialParse = true; - } - - // We do not proceed if the parser is in a "partial" state because - // the layer ordering needs to be respected when calculating text - // collisions. Although, at this point, we requested all the resources - // needed by this tile. - if (partialParse) { - return nullptr; - } - - bucket->addFeatures( - reinterpret_cast(&tile), *style.spriteAtlas, *style.sprite, *style.glyphAtlas, *style.glyphStore); - - return bucket->hasData() ? std::move(bucket) : nullptr; -} - -} diff --git a/src/mbgl/map/tile_parser.hpp b/src/mbgl/map/tile_parser.hpp deleted file mode 100644 index 63c1fd72a..000000000 --- a/src/mbgl/map/tile_parser.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef MBGL_MAP_TILE_PARSER -#define MBGL_MAP_TILE_PARSER - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace mbgl { - -class Bucket; -class FontStack; -class Style; -class StyleBucket; -class StyleLayoutFill; -class StyleLayoutRaster; -class StyleLayoutLine; -class StyleLayoutSymbol; -class TileWorker; - -class TileParser : private util::noncopyable { -public: - TileParser(const GeometryTile&, TileWorker&, Style&); - ~TileParser(); - -public: - void parse(); - inline bool isPartialParse() const { - return partialParse; - } - -private: - bool obsolete() const; - - std::unique_ptr createBucket(const StyleBucket&); - std::unique_ptr createFillBucket(const GeometryTileLayer&, const StyleBucket&); - std::unique_ptr createLineBucket(const GeometryTileLayer&, const StyleBucket&); - std::unique_ptr createSymbolBucket(const GeometryTileLayer&, const StyleBucket&); - - template - void addBucketGeometries(Bucket&, const GeometryTileLayer&, const FilterExpression&); - - const GeometryTile& geometryTile; - TileWorker& tile; - - // Cross-thread shared data. - Style& style; - - bool partialParse; -}; - -} - -#endif diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 1991ab188..a70e5a772 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -1,9 +1,13 @@ #include #include -#include #include #include #include +#include +#include +#include +#include +#include using namespace mbgl; @@ -12,11 +16,12 @@ TileWorker::TileWorker(const TileID& id_, const uint16_t maxZoom_, const std::atomic& state_, std::unique_ptr collision_) - : id(id_), - style(style_), + : style(style_), + id(id_), maxZoom(maxZoom_), state(state_), collision(std::move(collision_)) { + assert(style.sprite); } TileWorker::~TileWorker() { @@ -53,13 +58,36 @@ size_t TileWorker::countBuckets() const { } TileParseResult TileWorker::parse(const GeometryTile& geometryTile) { - // Parsing creates state that is encapsulated in TileParser. While parsing, - // the TileParser object writes results into this objects. All other state - // is going to be discarded afterwards. - TileParser parser(geometryTile, *this, style); - parser.parse(); + for (const auto& layer_desc : style.layers) { + // Cancel early when parsing. + if (obsolete()) { + return TileData::State::obsolete; + } - if (parser.isPartialParse()) { + if (layer_desc->isBackground()) { + // background is a special, fake bucket + continue; + } + + if (layer_desc->bucket) { + // This is a singular layer. Check if this bucket already exists. If not, + // parse this bucket. + if (getBucket(*layer_desc)) { + continue; + } + + std::unique_ptr bucket = createBucket(*layer_desc->bucket, geometryTile); + if (bucket) { + // Bucket creation might fail because the data tile may not + // contain any data that falls into this bucket. + setBucket(*layer_desc, std::move(bucket)); + } + } else { + Log::Warning(Event::ParseTile, "layer '%s' does not have buckets", layer_desc->id.c_str()); + } + } + + if (isPartialParse()) { return TileData::State::partial; } else { return TileData::State::parsed; @@ -76,3 +104,175 @@ void TileWorker::redoPlacement(float angle, bool collisionDebug) { } } } + +bool TileWorker::obsolete() const { + return getState() == TileData::State::obsolete; +} + +template +struct PropertyEvaluator { + typedef T result_type; + PropertyEvaluator(float z_) : z(z_) {} + + template ::value, int>::type = 0> + T operator()(const P &value) const { + return value; + } + + T operator()(const Function &value) const { + return mapbox::util::apply_visitor(FunctionEvaluator(z), value); + } + + template ::value, int>::type = 0> + T operator()(const P &) const { + return T(); + } + +private: + const float z; +}; + +template +void applyLayoutProperty(PropertyKey key, const ClassProperties &classProperties, T &target, const float z) { + auto it = classProperties.properties.find(key); + if (it != classProperties.properties.end()) { + const PropertyEvaluator evaluator(z); + target = mapbox::util::apply_visitor(evaluator, it->second); + } +} + +std::unique_ptr TileWorker::createBucket(const StyleBucket& bucketDesc, const GeometryTile& geometryTile) { + // Skip this bucket if we are to not render this + if (id.z < std::floor(bucketDesc.min_zoom) && std::floor(bucketDesc.min_zoom) < maxZoom) return nullptr; + if (id.z >= std::ceil(bucketDesc.max_zoom)) return nullptr; + if (bucketDesc.visibility == mbgl::VisibilityType::None) return nullptr; + + auto layer = geometryTile.getLayer(bucketDesc.source_layer); + if (layer) { + if (bucketDesc.type == StyleLayerType::Fill) { + return createFillBucket(*layer, bucketDesc); + } else if (bucketDesc.type == StyleLayerType::Line) { + return createLineBucket(*layer, bucketDesc); + } else if (bucketDesc.type == StyleLayerType::Symbol) { + return createSymbolBucket(*layer, bucketDesc); + } else if (bucketDesc.type == StyleLayerType::Raster) { + return nullptr; + } else { + Log::Warning(Event::ParseTile, "unknown bucket render type for layer '%s' (source layer '%s')", + bucketDesc.name.c_str(), bucketDesc.source_layer.c_str()); + } + } else { + // The layer specified in the bucket does not exist. Do nothing. + if (debug::tileParseWarnings) { + Log::Warning(Event::ParseTile, "layer '%s' does not exist in tile %d/%d/%d", + bucketDesc.source_layer.c_str(), id.z, id.x, id.y); + } + } + + return nullptr; +} + +template +void TileWorker::addBucketGeometries(Bucket& bucket, const GeometryTileLayer& layer, const FilterExpression &filter) { + for (std::size_t i = 0; i < layer.featureCount(); i++) { + auto feature = layer.getFeature(i); + + if (obsolete()) + return; + + GeometryTileFeatureExtractor extractor(*feature); + if (!evaluate(filter, extractor)) + continue; + + bucket->addGeometry(feature->getGeometries()); + } +} + +std::unique_ptr TileWorker::createFillBucket(const GeometryTileLayer& layer, + const StyleBucket& bucket_desc) { + auto bucket = std::make_unique(fillVertexBuffer, + triangleElementsBuffer, + lineElementsBuffer); + addBucketGeometries(bucket, layer, bucket_desc.filter); + return bucket->hasData() ? std::move(bucket) : nullptr; +} + +std::unique_ptr TileWorker::createLineBucket(const GeometryTileLayer& layer, + const StyleBucket& bucket_desc) { + auto bucket = std::make_unique(lineVertexBuffer, + triangleElementsBuffer); + + const float z = id.z; + auto& layout = bucket->layout; + + applyLayoutProperty(PropertyKey::LineCap, bucket_desc.layout, layout.cap, z); + applyLayoutProperty(PropertyKey::LineJoin, bucket_desc.layout, layout.join, z); + applyLayoutProperty(PropertyKey::LineMiterLimit, bucket_desc.layout, layout.miter_limit, z); + applyLayoutProperty(PropertyKey::LineRoundLimit, bucket_desc.layout, layout.round_limit, z); + + addBucketGeometries(bucket, layer, bucket_desc.filter); + return bucket->hasData() ? std::move(bucket) : nullptr; +} + +std::unique_ptr TileWorker::createSymbolBucket(const GeometryTileLayer& layer, + const StyleBucket& bucket_desc) { + auto bucket = std::make_unique(*getCollision(), id.overscaling); + + const float z = id.z; + auto& layout = bucket->layout; + + applyLayoutProperty(PropertyKey::SymbolPlacement, bucket_desc.layout, layout.placement, z); + if (layout.placement == PlacementType::Line) { + layout.icon.rotation_alignment = RotationAlignmentType::Map; + layout.text.rotation_alignment = RotationAlignmentType::Map; + }; + applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, layout.min_distance, z); + applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, layout.avoid_edges, z); + + applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, layout.icon.allow_overlap, z); + applyLayoutProperty(PropertyKey::IconIgnorePlacement, bucket_desc.layout, layout.icon.ignore_placement, z); + applyLayoutProperty(PropertyKey::IconOptional, bucket_desc.layout, layout.icon.optional, z); + applyLayoutProperty(PropertyKey::IconRotationAlignment, bucket_desc.layout, layout.icon.rotation_alignment, z); + applyLayoutProperty(PropertyKey::IconMaxSize, bucket_desc.layout, layout.icon.max_size, z); + applyLayoutProperty(PropertyKey::IconImage, bucket_desc.layout, layout.icon.image, z); + applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, layout.icon.padding, z); + applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, layout.icon.rotate, z); + applyLayoutProperty(PropertyKey::IconKeepUpright, bucket_desc.layout, layout.icon.keep_upright, z); + applyLayoutProperty(PropertyKey::IconOffset, bucket_desc.layout, layout.icon.offset, z); + + applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, layout.text.rotation_alignment, z); + applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, layout.text.field, z); + applyLayoutProperty(PropertyKey::TextFont, bucket_desc.layout, layout.text.font, z); + applyLayoutProperty(PropertyKey::TextMaxSize, bucket_desc.layout, layout.text.max_size, z); + applyLayoutProperty(PropertyKey::TextMaxWidth, bucket_desc.layout, layout.text.max_width, z); + applyLayoutProperty(PropertyKey::TextLineHeight, bucket_desc.layout, layout.text.line_height, z); + applyLayoutProperty(PropertyKey::TextLetterSpacing, bucket_desc.layout, layout.text.letter_spacing, z); + applyLayoutProperty(PropertyKey::TextMaxAngle, bucket_desc.layout, layout.text.max_angle, z); + applyLayoutProperty(PropertyKey::TextRotate, bucket_desc.layout, layout.text.rotate, z); + applyLayoutProperty(PropertyKey::TextPadding, bucket_desc.layout, layout.text.padding, z); + applyLayoutProperty(PropertyKey::TextIgnorePlacement, bucket_desc.layout, layout.text.ignore_placement, z); + applyLayoutProperty(PropertyKey::TextOptional, bucket_desc.layout, layout.text.optional, z); + applyLayoutProperty(PropertyKey::TextJustify, bucket_desc.layout, layout.text.justify, z); + applyLayoutProperty(PropertyKey::TextAnchor, bucket_desc.layout, layout.text.anchor, z); + applyLayoutProperty(PropertyKey::TextKeepUpright, bucket_desc.layout, layout.text.keep_upright, z); + applyLayoutProperty(PropertyKey::TextTransform, bucket_desc.layout, layout.text.transform, z); + applyLayoutProperty(PropertyKey::TextOffset, bucket_desc.layout, layout.text.offset, z); + applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, layout.text.allow_overlap, z); + + if (bucket->needsDependencies(layer, bucket_desc.filter, *style.glyphStore, *style.sprite)) { + partialParse = true; + } + + // We do not proceed if the parser is in a "partial" state because + // the layer ordering needs to be respected when calculating text + // collisions. Although, at this point, we requested all the resources + // needed by this tile. + if (partialParse) { + return nullptr; + } + + bucket->addFeatures( + reinterpret_cast(this), *style.spriteAtlas, *style.sprite, *style.glyphAtlas, *style.glyphStore); + + return bucket->hasData() ? std::move(bucket) : nullptr; +} diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp index 420b0bf9f..c3f131ccd 100644 --- a/src/mbgl/map/tile_worker.hpp +++ b/src/mbgl/map/tile_worker.hpp @@ -7,7 +7,9 @@ #include #include #include +#include +#include #include #include #include @@ -18,6 +20,8 @@ class CollisionTile; class GeometryTile; class Style; class Bucket; +class StyleBucket; +class GeometryTileLayer; using TileParseResult = mapbox::util::variant< TileData::State, // success @@ -44,14 +48,32 @@ public: return collision.get(); } + inline bool isPartialParse() const { + return partialParse; + } + TileParseResult parse(const GeometryTile&); void redoPlacement(float angle, bool collisionDebug); - const TileID id; Style& style; + +private: + bool obsolete() const; + + std::unique_ptr createBucket(const StyleBucket&, const GeometryTile&); + std::unique_ptr createFillBucket(const GeometryTileLayer&, const StyleBucket&); + std::unique_ptr createLineBucket(const GeometryTileLayer&, const StyleBucket&); + std::unique_ptr createSymbolBucket(const GeometryTileLayer&, const StyleBucket&); + + template + void addBucketGeometries(Bucket&, const GeometryTileLayer&, const FilterExpression&); + + const TileID id; const uint16_t maxZoom; const std::atomic& state; + bool partialParse = false; + FillVertexBuffer fillVertexBuffer; LineVertexBuffer lineVertexBuffer;