summaryrefslogtreecommitdiff
path: root/src/mbgl/tile/tile_worker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/tile/tile_worker.cpp')
-rw-r--r--src/mbgl/tile/tile_worker.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/mbgl/tile/tile_worker.cpp b/src/mbgl/tile/tile_worker.cpp
new file mode 100644
index 0000000000..917b61fde9
--- /dev/null
+++ b/src/mbgl/tile/tile_worker.cpp
@@ -0,0 +1,180 @@
+#include <mbgl/text/collision_tile.hpp>
+#include <mbgl/tile/tile_worker.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/style/style_layer.hpp>
+#include <mbgl/style/style_bucket_parameters.hpp>
+#include <mbgl/layer/background_layer.hpp>
+#include <mbgl/layer/custom_layer.hpp>
+#include <mbgl/layer/symbol_layer.hpp>
+#include <mbgl/sprite/sprite_atlas.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/platform/log.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/util/exception.hpp>
+#include <utility>
+
+using namespace mbgl;
+
+TileWorker::TileWorker(TileID id_,
+ std::string sourceID_,
+ SpriteStore& spriteStore_,
+ GlyphAtlas& glyphAtlas_,
+ GlyphStore& glyphStore_,
+ const std::atomic<TileData::State>& state_,
+ const MapMode mode_)
+ : id(id_),
+ sourceID(std::move(sourceID_)),
+ spriteStore(spriteStore_),
+ glyphAtlas(glyphAtlas_),
+ glyphStore(glyphStore_),
+ state(state_),
+ mode(mode_) {
+}
+
+TileWorker::~TileWorker() {
+ glyphAtlas.removeGlyphs(reinterpret_cast<uintptr_t>(this));
+}
+
+TileParseResult TileWorker::parseAllLayers(std::vector<std::unique_ptr<StyleLayer>> layers_,
+ std::unique_ptr<const GeometryTile> geometryTile,
+ PlacementConfig config) {
+ // We're doing a fresh parse of the tile, because the underlying data has changed.
+ pending.clear();
+ placementPending.clear();
+ partialParse = false;
+
+ // Store the layers for use in redoPlacement.
+ layers = std::move(layers_);
+
+ // We're storing a set of bucket names we've parsed to avoid parsing a bucket twice that is
+ // referenced from more than one layer
+ std::set<std::string> parsed;
+
+ for (auto i = layers.rbegin(); i != layers.rend(); i++) {
+ const StyleLayer* layer = i->get();
+ if (parsed.find(layer->bucketName()) == parsed.end()) {
+ parsed.emplace(layer->bucketName());
+ parseLayer(layer, *geometryTile);
+ }
+ }
+
+ result.state = pending.empty() ? TileData::State::parsed : TileData::State::partial;
+
+ if (result.state == TileData::State::parsed) {
+ placeLayers(config);
+ }
+
+ return std::move(result);
+}
+
+TileParseResult TileWorker::parsePendingLayers(const PlacementConfig config) {
+ // Try parsing the remaining layers that we couldn't parse in the first step due to missing
+ // dependencies.
+ for (auto it = pending.begin(); it != pending.end();) {
+ auto& layer = *it->first;
+ auto bucket = dynamic_cast<SymbolBucket*>(it->second.get());
+ assert(bucket); // Only symbol layers can be pending, so the dynamic cast should never fail.
+
+ if (!bucket->needsDependencies(glyphStore, spriteStore)) {
+ bucket->addFeatures(reinterpret_cast<uintptr_t>(this),
+ *layer.spriteAtlas,
+ glyphAtlas,
+ glyphStore);
+ placementPending.emplace(layer.bucketName(), std::move(it->second));
+ pending.erase(it++);
+ continue;
+ }
+
+ // Advance the iterator here; we're skipping this when erasing an element from this list.
+ ++it;
+ }
+
+ result.state = pending.empty() ? TileData::State::parsed : TileData::State::partial;
+
+ if (result.state == TileData::State::parsed) {
+ placeLayers(config);
+ }
+
+ return std::move(result);
+}
+
+void TileWorker::placeLayers(const PlacementConfig config) {
+ redoPlacement(&placementPending, config);
+ for (auto &p : placementPending) {
+ p.second->swapRenderData();
+ insertBucket(p.first, std::move(p.second));
+ }
+ placementPending.clear();
+}
+
+void TileWorker::redoPlacement(
+ const std::unordered_map<std::string, std::unique_ptr<Bucket>>* buckets,
+ PlacementConfig config) {
+
+ CollisionTile collisionTile(config);
+
+ for (auto i = layers.rbegin(); i != layers.rend(); i++) {
+ const auto it = buckets->find((*i)->id);
+ if (it != buckets->end()) {
+ it->second->placeFeatures(collisionTile);
+ }
+ }
+}
+
+void TileWorker::parseLayer(const StyleLayer* layer, const GeometryTile& geometryTile) {
+ // Cancel early when parsing.
+ if (state == TileData::State::obsolete)
+ return;
+
+ // Background and custom layers are special cases.
+ if (layer->is<BackgroundLayer>() || layer->is<CustomLayer>())
+ return;
+
+ // Skip this bucket if we are to not render this
+ if ((layer->source != sourceID) ||
+ (id.z < std::floor(layer->minZoom)) ||
+ (id.z >= std::ceil(layer->maxZoom)) ||
+ (layer->visibility == VisibilityType::None)) {
+ return;
+ }
+
+ auto geometryLayer = geometryTile.getLayer(layer->sourceLayer);
+ if (!geometryLayer) {
+ // 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",
+ layer->sourceLayer.c_str(), id.z, id.x, id.y);
+ }
+ return;
+ }
+
+ StyleBucketParameters parameters(id,
+ *geometryLayer,
+ state,
+ reinterpret_cast<uintptr_t>(this),
+ partialParse,
+ spriteStore,
+ glyphAtlas,
+ glyphStore,
+ mode);
+
+ std::unique_ptr<Bucket> bucket = layer->createBucket(parameters);
+
+ if (layer->is<SymbolLayer>()) {
+ if (partialParse) {
+ // We cannot parse this bucket yet. Instead, we're saving it for later.
+ pending.emplace_back(layer->as<SymbolLayer>(), std::move(bucket));
+ } else {
+ placementPending.emplace(layer->bucketName(), std::move(bucket));
+ }
+ } else {
+ insertBucket(layer->bucketName(), std::move(bucket));
+ }
+}
+
+void TileWorker::insertBucket(const std::string& name, std::unique_ptr<Bucket> bucket) {
+ if (bucket->hasData()) {
+ result.buckets.emplace(name, std::move(bucket));
+ }
+}