diff options
Diffstat (limited to 'src/mbgl/map')
25 files changed, 40 insertions, 2055 deletions
diff --git a/src/mbgl/map/geometry_tile.cpp b/src/mbgl/map/geometry_tile.cpp deleted file mode 100644 index 82affc689f..0000000000 --- a/src/mbgl/map/geometry_tile.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include <mbgl/map/geometry_tile.hpp> -#include <mbgl/style/filter_expression.hpp> -#include <mbgl/style/filter_expression_private.hpp> - -namespace mbgl { - -optional<Value> GeometryTileFeatureExtractor::getValue(const std::string& key) const { - if (key == "$type") { - return Value(uint64_t(feature.getType())); - } - - return feature.getValue(key); -} - -template bool evaluate(const FilterExpression&, const GeometryTileFeatureExtractor&); - -} // namespace mbgl diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/map/geometry_tile.hpp deleted file mode 100644 index 5cb2f96fdc..0000000000 --- a/src/mbgl/map/geometry_tile.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef MBGL_MAP_GEOMETRY_TILE -#define MBGL_MAP_GEOMETRY_TILE - -#include <mapbox/variant.hpp> - -#include <mbgl/style/value.hpp> -#include <mbgl/util/chrono.hpp> -#include <mbgl/util/ptr.hpp> -#include <mbgl/util/vec.hpp> -#include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/optional.hpp> - -#include <cstdint> -#include <string> -#include <vector> -#include <functional> - -namespace mbgl { - -enum class FeatureType : uint8_t { - Unknown = 0, - Point = 1, - LineString = 2, - Polygon = 3 -}; - -typedef std::vector<std::vector<Coordinate>> GeometryCollection; - -class GeometryTileFeature : private util::noncopyable { -public: - virtual ~GeometryTileFeature() = default; - virtual FeatureType getType() const = 0; - virtual optional<Value> getValue(const std::string& key) const = 0; - virtual GeometryCollection getGeometries() const = 0; - virtual uint32_t getExtent() const = 0; -}; - -class GeometryTileLayer : private util::noncopyable { -public: - virtual ~GeometryTileLayer() = default; - virtual std::size_t featureCount() const = 0; - virtual util::ptr<const GeometryTileFeature> getFeature(std::size_t) const = 0; -}; - -class GeometryTile : private util::noncopyable { -public: - virtual ~GeometryTile() = default; - virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0; -}; - -class FileRequest; - -class GeometryTileMonitor : private util::noncopyable { -public: - virtual ~GeometryTileMonitor() = default; - - using Callback = std::function<void (std::exception_ptr, - std::unique_ptr<GeometryTile>, - optional<SystemTimePoint> modified, - optional<SystemTimePoint> expires)>; - /* - * Monitor the tile held by this object for changes. When the tile is loaded for the first time, - * or updates, the callback is executed. If an error occurs, the first parameter will be set. - * Otherwise it will be null. If there is no data for the requested tile, the second parameter - * will be null. - * - * To cease monitoring, release the returned Request. - */ - virtual std::unique_ptr<FileRequest> monitorTile(const Callback&) = 0; -}; - -class GeometryTileFeatureExtractor { -public: - GeometryTileFeatureExtractor(const GeometryTileFeature& feature_) - : feature(feature_) {} - - optional<Value> getValue(const std::string& key) const; - -private: - const GeometryTileFeature& feature; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 7e0fdd29fe..c3123fb3be 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -462,6 +462,11 @@ AnnotationIDs Map::addShapeAnnotations(const std::vector<ShapeAnnotation>& annot return result; } +void Map::updatePointAnnotation(AnnotationID annotationId, const PointAnnotation& annotation) { + data->getAnnotationManager()->updatePointAnnotation(annotationId, annotation, getMaxZoom()); + update(Update::Annotations); +} + void Map::removeAnnotation(AnnotationID annotation) { removeAnnotations({ annotation }); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 03da5ee321..f9397d4f78 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -16,9 +16,10 @@ #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/sprite/sprite_store.hpp> -#include <mbgl/util/gl_object_store.hpp> +#include <mbgl/gl/gl_object_store.hpp> +#include <mbgl/gl/texture_pool.hpp> + #include <mbgl/util/worker.hpp> -#include <mbgl/util/texture_pool.hpp> #include <mbgl/util/exception.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/mapbox.hpp> @@ -27,18 +28,16 @@ namespace mbgl { -MapContext::MapContext(View& view_, FileSource& fileSource, MapMode mode_, GLContextMode contextMode_, const float pixelRatio_) +MapContext::MapContext(View& view_, FileSource& fileSource_, MapMode mode_, GLContextMode contextMode_, const float pixelRatio_) : view(view_), + fileSource(fileSource_), dataPtr(std::make_unique<MapData>(mode_, contextMode_, pixelRatio_)), data(*dataPtr), asyncUpdate([this] { update(); }), asyncInvalidate([&view_] { view_.invalidate(); }), - texturePool(std::make_unique<TexturePool>()) { + texturePool(std::make_unique<gl::TexturePool>()) { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - util::ThreadContext::setFileSource(&fileSource); - util::ThreadContext::setGLObjectStore(&glObjectStore); - view.activate(); } @@ -95,7 +94,7 @@ void MapContext::setStyleURL(const std::string& url) { styleURL = url; styleJSON.clear(); - style = std::make_unique<Style>(data); + style = std::make_unique<Style>(data, fileSource); const size_t pos = styleURL.rfind('/'); std::string base = ""; @@ -103,8 +102,7 @@ void MapContext::setStyleURL(const std::string& url) { base = styleURL.substr(0, pos + 1); } - FileSource* fs = util::ThreadContext::getFileSource(); - styleRequest = fs->request(Resource::style(styleURL), [this, base](Response res) { + styleRequest = fileSource.request(Resource::style(styleURL), [this, base](Response res) { if (res.error) { if (res.error->reason == Response::Error::Reason::NotFound && util::mapbox::isMapboxURL(styleURL)) { @@ -113,14 +111,11 @@ void MapContext::setStyleURL(const std::string& url) { Log::Error(Event::Setup, "loading style failed: %s", res.error->message.c_str()); data.loading = false; } + } else if (res.notModified || res.noContent) { return; + } else { + loadStyleJSON(*res.data, base); } - - if (res.notModified) { - return; - } - - loadStyleJSON(*res.data, base); }); } @@ -132,7 +127,7 @@ void MapContext::setStyleJSON(const std::string& json, const std::string& base) styleURL.clear(); styleJSON.clear(); - style = std::make_unique<Style>(data); + style = std::make_unique<Style>(data, fileSource); loadStyleJSON(json, base); } @@ -241,7 +236,7 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame) // Cleanup OpenGL objects that we abandoned since the last render call. glObjectStore.performCleanup(); - if (!painter) painter = std::make_unique<Painter>(data, transformState); + if (!painter) painter = std::make_unique<Painter>(data, transformState, glObjectStore); painter->render(*style, frame, data.getAnnotationManager()->getSpriteAtlas()); if (data.mode == MapMode::Still) { diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index dd0c2de465..83ab71c86e 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -8,9 +8,9 @@ #include <mbgl/map/map_data.hpp> #include <mbgl/style/style.hpp> #include <mbgl/util/async_task.hpp> -#include <mbgl/util/gl_object_store.hpp> #include <mbgl/util/ptr.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/gl/gl_object_store.hpp> #include <vector> @@ -18,11 +18,12 @@ namespace mbgl { class View; class MapData; -class TexturePool; class Painter; class SpriteImage; class FileRequest; +namespace gl { class TexturePool; } + struct FrameData { std::array<uint16_t, 2> framebufferSize; }; @@ -77,16 +78,17 @@ private: void loadStyleJSON(const std::string& json, const std::string& base); View& view; + FileSource& fileSource; std::unique_ptr<MapData> dataPtr; MapData& data; - util::GLObjectStore glObjectStore; + gl::GLObjectStore glObjectStore; Update updateFlags = Update::Nothing; util::AsyncTask asyncUpdate; util::AsyncTask asyncInvalidate; - std::unique_ptr<TexturePool> texturePool; + std::unique_ptr<gl::TexturePool> texturePool; std::unique_ptr<Painter> painter; std::unique_ptr<Style> style; diff --git a/src/mbgl/map/raster_tile_data.cpp b/src/mbgl/map/raster_tile_data.cpp deleted file mode 100644 index f9f5480197..0000000000 --- a/src/mbgl/map/raster_tile_data.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include <mbgl/map/raster_tile_data.hpp> -#include <mbgl/map/source.hpp> -#include <mbgl/storage/resource.hpp> -#include <mbgl/storage/response.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/util/worker.hpp> -#include <mbgl/util/work_request.hpp> - -using namespace mbgl; - -RasterTileData::RasterTileData(const TileID& id_, - float pixelRatio, - const std::string& urlTemplate, - TexturePool &texturePool_, - Worker& worker_, - const std::function<void(std::exception_ptr)>& callback) - : TileData(id_), - texturePool(texturePool_), - worker(worker_) { - state = State::loading; - - const Resource resource = Resource::tile(urlTemplate, pixelRatio, id.x, id.y, id.sourceZ); - req = util::ThreadContext::getFileSource()->request(resource, [callback, this](Response res) { - if (res.error) { - std::exception_ptr error; - if (res.error->reason == Response::Error::Reason::NotFound) { - // This is a 404 response. We're treating these as empty tiles. - workRequest.reset(); - state = State::parsed; - bucket.reset(); - } else { - // This is a different error, e.g. a connection or server error. - error = std::make_exception_ptr(std::runtime_error(res.error->message)); - } - callback(error); - return; - } - - modified = res.modified; - expires = res.expires; - - if (res.notModified) { - // We got the same data again. Abort early. - return; - } - - if (state == State::loading) { - // Only overwrite the state when we didn't have a previous tile. - state = State::loaded; - } - - workRequest.reset(); - workRequest = worker.parseRasterTile(std::make_unique<RasterBucket>(texturePool), res.data, [this, callback] (RasterTileParseResult result) { - workRequest.reset(); - if (state != State::loaded) { - return; - } - - std::exception_ptr error; - if (result.is<std::unique_ptr<Bucket>>()) { - state = State::parsed; - bucket = std::move(result.get<std::unique_ptr<Bucket>>()); - } else { - error = result.get<std::exception_ptr>(); - state = State::obsolete; - bucket.reset(); - } - - callback(error); - }); - }); -} - -RasterTileData::~RasterTileData() { - cancel(); -} - -Bucket* RasterTileData::getBucket(StyleLayer const&) { - return bucket.get(); -} - -void RasterTileData::cancel() { - if (state != State::obsolete) { - state = State::obsolete; - } - req = nullptr; - workRequest.reset(); -} diff --git a/src/mbgl/map/raster_tile_data.hpp b/src/mbgl/map/raster_tile_data.hpp deleted file mode 100644 index e68fbc94c5..0000000000 --- a/src/mbgl/map/raster_tile_data.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef MBGL_MAP_RASTER_TILE_DATA -#define MBGL_MAP_RASTER_TILE_DATA - -#include <mbgl/map/tile_data.hpp> -#include <mbgl/renderer/raster_bucket.hpp> - -namespace mbgl { - -class FileRequest; -class StyleLayer; -class TexturePool; -class WorkRequest; - -class RasterTileData : public TileData { -public: - RasterTileData(const TileID&, - float pixelRatio, - const std::string& urlTemplate, - TexturePool&, - Worker&, - const std::function<void(std::exception_ptr)>& callback); - ~RasterTileData(); - - void cancel() override; - Bucket* getBucket(StyleLayer const &layer_desc) override; - -private: - TexturePool& texturePool; - Worker& worker; - std::unique_ptr<FileRequest> req; - std::unique_ptr<Bucket> bucket; - std::unique_ptr<WorkRequest> workRequest; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp deleted file mode 100644 index 7f9b47440b..0000000000 --- a/src/mbgl/map/source.cpp +++ /dev/null @@ -1,563 +0,0 @@ -#include <mbgl/map/source.hpp> -#include <mbgl/map/map_data.hpp> -#include <mbgl/map/transform.hpp> -#include <mbgl/map/tile.hpp> -#include <mbgl/map/vector_tile.hpp> -#include <mbgl/annotation/annotation_tile.hpp> -#include <mbgl/tile/geojson_tile.hpp> -#include <mbgl/renderer/painter.hpp> -#include <mbgl/util/exception.hpp> -#include <mbgl/util/constants.hpp> -#include <mbgl/storage/resource.hpp> -#include <mbgl/storage/response.hpp> -#include <mbgl/util/math.hpp> -#include <mbgl/util/box.hpp> -#include <mbgl/util/tile_coordinate.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/style/style_layer.hpp> -#include <mbgl/style/style_update_parameters.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/util/std.hpp> -#include <mbgl/util/token.hpp> -#include <mbgl/util/string.hpp> -#include <mbgl/util/tile_cover.hpp> - -#include <mbgl/map/vector_tile_data.hpp> -#include <mbgl/map/raster_tile_data.hpp> -#include <mbgl/style/style.hpp> -#include <mbgl/style/style_parser.hpp> -#include <mbgl/gl/debugging.hpp> - -#include <mapbox/geojsonvt.hpp> -#include <mapbox/geojsonvt/convert.hpp> - -#include <rapidjson/error/en.h> - -#include <algorithm> -#include <sstream> - -namespace mbgl { - -Source::Source(SourceType type_, - const std::string& id_, - const std::string& url_, - uint16_t tileSize_, - std::unique_ptr<SourceInfo>&& info_, - std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>&& geojsonvt_) - : type(type_), - id(id_), - url(url_), - tileSize(tileSize_), - info(std::move(info_)), - geojsonvt(std::move(geojsonvt_)) { -} - -Source::~Source() = default; - -bool Source::isLoaded() const { - if (!loaded) return false; - - for (const auto& tile : tiles) { - if (tile.second->data->getState() != TileData::State::parsed) { - return false; - } - } - - return true; -} - -bool Source::isLoading() const { - return !loaded && req.operator bool(); -} - -// Note: This is a separate function that must be called exactly once after creation -// The reason this isn't part of the constructor is that calling shared_from_this() in -// the constructor fails. -void Source::load() { - if (url.empty()) { - // In case there is no URL set, we assume that we already have all of the data because the - // TileJSON was specified inline in the stylesheet. - loaded = true; - return; - } - - if (req) { - // We don't have a SourceInfo object yet, but there's already a request underway to load - // the data. - return; - } - - // URL may either be a TileJSON file, or a GeoJSON file. - FileSource* fs = util::ThreadContext::getFileSource(); - req = fs->request(Resource::source(url), [this](Response res) { - if (res.error) { - observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message))); - return; - } - - if (res.notModified) { - // We got the same data back as last time. Abort early. - return; - } - - bool reloadTiles = false; - - if (type == SourceType::Vector || type == SourceType::Raster) { - std::unique_ptr<SourceInfo> newInfo; - - // Create a new copy of the SourceInfo object that holds the base values we've parsed - // from the stylesheet. Then merge in the values parsed from the TileJSON we retrieved - // via the URL. - try { - newInfo = StyleParser::parseTileJSON(*res.data, url, type); - } catch (...) { - observer->onSourceError(*this, std::current_exception()); - return; - } - - // Check whether previous information specifies different tile - if (info && info->tiles != newInfo->tiles) { - reloadTiles = true; - - // Tile size changed: We need to recalculate the tiles we need to load because we - // might have to load tiles for a different zoom level - // This is done automatically when we trigger the onSourceLoaded observer below. - - // Min/Max zoom changed: We need to recalculate what tiles to load, if we have tiles - // loaded that are outside the new zoom range - // This is done automatically when we trigger the onSourceLoaded observer below. - - // Attribution changed: We need to notify the embedding application that this - // changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723 - // This is not yet implemented. - - // Center/bounds changed: We're not using these values currently - } - - info = std::move(newInfo); - } else if (type == SourceType::GeoJSON) { - info = std::make_unique<SourceInfo>(); - - rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d; - d.Parse<0>(res.data->c_str()); - - if (d.HasParseError()) { - std::stringstream message; - message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError()); - observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(message.str()))); - return; - } - - geojsonvt = StyleParser::parseGeoJSON(d); - reloadTiles = true; - } - - if (reloadTiles) { - // Tile information changed because we got new GeoJSON data, or a new tile URL. - tilePtrs.clear(); - tileDataMap.clear(); - tiles.clear(); - cache.clear(); - } - - loaded = true; - observer->onSourceLoaded(*this); - }); -} - -void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) { - for (const auto& pair : tiles) { - Tile &tile = *pair.second; - transform.matrixFor(tile.matrix, tile.id, std::min(static_cast<int8_t>(info->maxZoom), tile.id.z)); - matrix::multiply(tile.matrix, projMatrix, tile.matrix); - } -} - -void Source::drawClippingMasks(Painter &painter) { - for (const auto& pair : tiles) { - Tile &tile = *pair.second; - MBGL_DEBUG_GROUP(std::string { "mask: " } + std::string(tile.id)); - painter.drawClippingMask(tile.matrix, tile.clip); - } -} - -void Source::finishRender(Painter &painter) { - for (const auto& pair : tiles) { - Tile &tile = *pair.second; - painter.renderTileDebug(tile); - } -} - -std::forward_list<Tile*> Source::getLoadedTiles() const { - std::forward_list<Tile*> ptrs; - auto it = ptrs.before_begin(); - for (const auto& pair : tiles) { - if (pair.second->data->isReady()) { - it = ptrs.insert_after(it, pair.second.get()); - } - } - return ptrs; -} - -const std::vector<Tile*>& Source::getTiles() const { - return tilePtrs; -} - -TileData::State Source::hasTile(const TileID& tileID) { - auto it = tiles.find(tileID); - if (it != tiles.end()) { - Tile& tile = *it->second; - if (tile.id == tileID && tile.data) { - return tile.data->getState(); - } - } - - return TileData::State::invalid; -} - -bool Source::handlePartialTile(const TileID& tileID) { - auto it = tileDataMap.find(tileID.normalized()); - if (it == tileDataMap.end()) { - return true; - } - - auto tileData = it->second.lock(); - if (!tileData) { - return true; - } - - auto callback = std::bind(&Source::tileLoadingCallback, this, tileID, - std::placeholders::_1, false); - - return tileData->parsePending(callback); -} - -TileData::State Source::addTile(const TileID& tileID, const StyleUpdateParameters& parameters) { - const TileData::State state = hasTile(tileID); - - if (state != TileData::State::invalid) { - return state; - } - - auto newTile = std::make_unique<Tile>(tileID); - - // We couldn't find the tile in the list. Create a new one. - // Try to find the associated TileData object. - const TileID normalizedID = tileID.normalized(); - - auto it = tileDataMap.find(normalizedID); - if (it != tileDataMap.end()) { - // Create a shared_ptr handle. Note that this might be empty! - newTile->data = it->second.lock(); - } - - if (newTile->data && newTile->data->getState() == TileData::State::obsolete) { - // Do not consider the tile if it's already obsolete. - newTile->data.reset(); - } - - if (!newTile->data) { - newTile->data = cache.get(normalizedID.to_uint64()); - } - - if (!newTile->data) { - auto callback = std::bind(&Source::tileLoadingCallback, this, normalizedID, - std::placeholders::_1, true); - - // If we don't find working tile data, we're just going to load it. - if (type == SourceType::Raster) { - newTile->data = std::make_shared<RasterTileData>(normalizedID, - parameters.pixelRatio, - info->tiles.at(0), - parameters.texturePool, - parameters.worker, - callback); - } else { - std::unique_ptr<GeometryTileMonitor> monitor; - - if (type == SourceType::Vector) { - monitor = std::make_unique<VectorTileMonitor>(normalizedID, parameters.pixelRatio, info->tiles.at(0)); - } else if (type == SourceType::Annotations) { - monitor = std::make_unique<AnnotationTileMonitor>(normalizedID, parameters.data); - } else if (type == SourceType::GeoJSON) { - monitor = std::make_unique<GeoJSONTileMonitor>(geojsonvt.get(), normalizedID); - } else { - Log::Warning(Event::Style, "Source type '%s' is not implemented", SourceTypeClass(type).c_str()); - return TileData::State::invalid; - } - - newTile->data = std::make_shared<VectorTileData>(normalizedID, - std::move(monitor), - id, - parameters.style, - parameters.mode, - callback); - } - - tileDataMap.emplace(newTile->data->id, newTile->data); - } - - const auto newState = newTile->data->getState(); - tiles.emplace(tileID, std::move(newTile)); - return newState; -} - -double Source::getZoom(const TransformState& state) const { - double offset = std::log(util::tileSize / tileSize) / std::log(2); - return state.getZoom() + offset; -} - -int32_t Source::coveringZoomLevel(const TransformState& state) const { - double zoom = getZoom(state); - if (type == SourceType::Raster || type == SourceType::Video) { - zoom = ::round(zoom); - } else { - zoom = std::floor(zoom); - } - return util::clamp(zoom, state.getMinZoom(), state.getMaxZoom()); -} - -std::forward_list<TileID> Source::coveringTiles(const TransformState& state) const { - int32_t z = coveringZoomLevel(state); - - auto actualZ = z; - const bool reparseOverscaled = - type == SourceType::Vector || - type == SourceType::Annotations; - - if (z < info->minZoom) return {{}}; - if (z > info->maxZoom) z = info->maxZoom; - - // Map four viewport corners to pixel coordinates - box points = state.cornersToBox(z); - const TileCoordinate center = state.pointToCoordinate({ state.getWidth() / 2.0f, state.getHeight()/ 2.0f }).zoomTo(z); - - std::forward_list<TileID> covering_tiles = tileCover(z, points, reparseOverscaled ? actualZ : z); - - covering_tiles.sort([¢er](const TileID& a, const TileID& b) { - // Sorts by distance from the box center - return std::fabs(a.x - center.column) + std::fabs(a.y - center.row) < - std::fabs(b.x - center.column) + std::fabs(b.y - center.row); - }); - - return covering_tiles; -} - -/** - * Recursively find children of the given tile that are already loaded. - * - * @param id The tile ID that we should find children for. - * @param maxCoveringZoom The maximum zoom level of children to look for. - * @param retain An object that we add the found tiles to. - * - * @return boolean Whether the children found completely cover the tile. - */ -bool Source::findLoadedChildren(const TileID& tileID, int32_t maxCoveringZoom, std::forward_list<TileID>& retain) { - bool complete = true; - int32_t z = tileID.z; - auto ids = tileID.children(info->maxZoom); - for (const auto& child_id : ids) { - const TileData::State state = hasTile(child_id); - if (TileData::isReadyState(state)) { - retain.emplace_front(child_id); - } - if (state != TileData::State::parsed) { - complete = false; - if (z < maxCoveringZoom) { - // Go further down the hierarchy to find more unloaded children. - findLoadedChildren(child_id, maxCoveringZoom, retain); - } - } - } - return complete; -} - -/** - * Find a loaded parent of the given tile. - * - * @param id The tile ID that we should find children for. - * @param minCoveringZoom The minimum zoom level of parents to look for. - * @param retain An object that we add the found tiles to. - * - * @return boolean Whether a parent was found. - */ -void Source::findLoadedParent(const TileID& tileID, int32_t minCoveringZoom, std::forward_list<TileID>& retain) { - for (int32_t z = tileID.z - 1; z >= minCoveringZoom; --z) { - const TileID parent_id = tileID.parent(z, info->maxZoom); - const TileData::State state = hasTile(parent_id); - if (TileData::isReadyState(state)) { - retain.emplace_front(parent_id); - if (state == TileData::State::parsed) { - return; - } - } - } -} - -bool Source::update(const StyleUpdateParameters& parameters) { - bool allTilesUpdated = true; - - if (!loaded || parameters.animationTime <= updated) { - return allTilesUpdated; - } - - double zoom = coveringZoomLevel(parameters.transformState); - std::forward_list<TileID> required = coveringTiles(parameters.transformState); - - // Determine the overzooming/underzooming amounts. - int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info->minZoom, info->maxZoom); - int32_t maxCoveringZoom = util::clamp<int32_t>(zoom + 1, info->minZoom, info->maxZoom); - - // Retain is a list of tiles that we shouldn't delete, even if they are not - // the most ideal tile for the current viewport. This may include tiles like - // parent or child tiles that are *already* loaded. - std::forward_list<TileID> retain(required); - - // Add existing child/parent tiles if the actual tile is not yet loaded - for (const auto& tileID : required) { - TileData::State state = hasTile(tileID); - - switch (state) { - case TileData::State::partial: - if (parameters.shouldReparsePartialTiles) { - if (!handlePartialTile(tileID)) { - allTilesUpdated = false; - } - } - break; - case TileData::State::invalid: - state = addTile(tileID, parameters); - break; - default: - break; - } - - if (!TileData::isReadyState(state)) { - // The tile we require is not yet loaded. Try to find a parent or - // child tile that we already have. - - // First, try to find existing child tiles that completely cover the - // missing tile. - bool complete = findLoadedChildren(tileID, maxCoveringZoom, retain); - - // Then, if there are no complete child tiles, try to find existing - // parent tiles that completely cover the missing tile. - if (!complete) { - findLoadedParent(tileID, minCoveringZoom, retain); - } - } - } - - if (type != SourceType::Raster && cache.getSize() == 0) { - size_t conservativeCacheSize = ((float)parameters.transformState.getWidth() / util::tileSize) * - ((float)parameters.transformState.getHeight() / util::tileSize) * - (parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) * - 0.5; - cache.setSize(conservativeCacheSize); - } - - auto& tileCache = cache; - - // Remove tiles that we definitely don't need, i.e. tiles that are not on - // the required list. - std::set<TileID> retain_data; - util::erase_if(tiles, [this, &retain, &retain_data, &tileCache](std::pair<const TileID, std::unique_ptr<Tile>> &pair) { - Tile &tile = *pair.second; - bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end(); - if (!obsolete) { - retain_data.insert(tile.data->id); - } else if (type != SourceType::Raster && tile.data->getState() == TileData::State::parsed) { - // Partially parsed tiles are never added to the cache because otherwise - // they never get updated if the go out from the viewport and the pending - // resources arrive. - tileCache.add(tile.id.normalized().to_uint64(), tile.data); - } - return obsolete; - }); - - // Remove all the expired pointers from the set. - util::erase_if(tileDataMap, [&retain_data, &tileCache](std::pair<const TileID, std::weak_ptr<TileData>> &pair) { - const util::ptr<TileData> tile = pair.second.lock(); - if (!tile) { - return true; - } - - bool obsolete = retain_data.find(tile->id) == retain_data.end(); - if (obsolete) { - if (!tileCache.has(tile->id.normalized().to_uint64())) { - tile->cancel(); - } - return true; - } else { - return false; - } - }); - - updateTilePtrs(); - - for (auto& tilePtr : tilePtrs) { - tilePtr->data->redoPlacement( - { parameters.transformState.getAngle(), parameters.transformState.getPitch(), parameters.debugOptions & MapDebugOptions::Collision }, - [this]() { - observer->onPlacementRedone(); - }); - } - - updated = parameters.animationTime; - - return allTilesUpdated; -} - -void Source::updateTilePtrs() { - tilePtrs.clear(); - for (const auto& pair : tiles) { - tilePtrs.push_back(pair.second.get()); - } -} - -void Source::setCacheSize(size_t size) { - cache.setSize(size); -} - -void Source::onLowMemory() { - cache.clear(); -} - -void Source::setObserver(Observer* observer_) { - observer = observer_; -} - -void Source::tileLoadingCallback(const TileID& tileID, - std::exception_ptr error, - bool isNewTile) { - auto it = tileDataMap.find(tileID); - if (it == tileDataMap.end()) { - return; - } - - util::ptr<TileData> tileData = it->second.lock(); - if (!tileData) { - return; - } - - if (error) { - observer->onTileError(*this, tileID, error); - return; - } - - tileData->redoPlacement([this]() { - observer->onPlacementRedone(); - }); - observer->onTileLoaded(*this, tileID, isNewTile); -} - -void Source::dumpDebugLogs() const { - Log::Info(Event::General, "Source::id: %s", id.c_str()); - Log::Info(Event::General, "Source::loaded: %d", loaded); - - for (const auto& tile : tiles) { - tile.second->data->dumpDebugLogs(); - } -} - -} // namespace mbgl diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp deleted file mode 100644 index d9146c1fdb..0000000000 --- a/src/mbgl/map/source.hpp +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef MBGL_MAP_SOURCE -#define MBGL_MAP_SOURCE - -#include <mbgl/map/tile_cache.hpp> -#include <mbgl/map/source_info.hpp> - -#include <mbgl/util/mat4.hpp> -#include <mbgl/util/rapidjson.hpp> - -#include <forward_list> -#include <map> - -namespace mapbox { -namespace geojsonvt { -class GeoJSONVT; -} // namespace geojsonvt -} // namespace mapbox - -namespace mbgl { - -class StyleUpdateParameters; -class Painter; -class FileRequest; -class TransformState; -class Tile; -struct ClipID; -struct box; - -class Source : private util::noncopyable { -public: - class Observer { - public: - virtual ~Observer() = default; - - virtual void onSourceLoaded(Source&) {}; - virtual void onSourceError(Source&, std::exception_ptr) {}; - - virtual void onTileLoaded(Source&, const TileID&, bool /* isNewTile */) {}; - virtual void onTileError(Source&, const TileID&, std::exception_ptr) {}; - virtual void onPlacementRedone() {}; - }; - - Source(SourceType, - const std::string& id, - const std::string& url, - uint16_t tileSize, - std::unique_ptr<SourceInfo>&&, - std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>&&); - ~Source(); - - bool loaded = false; - void load(); - bool isLoading() const; - bool isLoaded() const; - - // Request or parse all the tiles relevant for the "TransformState". This method - // will return true if all the tiles were scheduled for updating of false if - // they were not. shouldReparsePartialTiles must be set to "true" if there is - // new data available that a tile in the "partial" state might be interested at. - bool update(const StyleUpdateParameters&); - - void updateMatrices(const mat4 &projMatrix, const TransformState &transform); - void drawClippingMasks(Painter &painter); - void finishRender(Painter &painter); - - std::forward_list<Tile *> getLoadedTiles() const; - const std::vector<Tile*>& getTiles() const; - - void setCacheSize(size_t); - void onLowMemory(); - - void setObserver(Observer* observer); - void dumpDebugLogs() const; - - const SourceType type; - const std::string id; - const std::string url; - uint16_t tileSize = util::tileSize; - bool enabled = false; - -private: - void tileLoadingCallback(const TileID&, - std::exception_ptr, - bool isNewTile); - bool handlePartialTile(const TileID&); - bool findLoadedChildren(const TileID&, int32_t maxCoveringZoom, std::forward_list<TileID>& retain); - void findLoadedParent(const TileID&, int32_t minCoveringZoom, std::forward_list<TileID>& retain); - int32_t coveringZoomLevel(const TransformState&) const; - std::forward_list<TileID> coveringTiles(const TransformState&) const; - - TileData::State addTile(const TileID&, const StyleUpdateParameters&); - TileData::State hasTile(const TileID&); - void updateTilePtrs(); - - double getZoom(const TransformState &state) const; - -private: - std::unique_ptr<const SourceInfo> info; - - std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> geojsonvt; - - // Stores the time when this source was most recently updated. - TimePoint updated = TimePoint::min(); - - std::map<TileID, std::unique_ptr<Tile>> tiles; - std::vector<Tile*> tilePtrs; - std::map<TileID, std::weak_ptr<TileData>> tileDataMap; - TileCache cache; - - std::unique_ptr<FileRequest> req; - - Observer nullObserver; - Observer* observer = &nullObserver; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/source_info.hpp b/src/mbgl/map/source_info.hpp deleted file mode 100644 index 2fb5c2466d..0000000000 --- a/src/mbgl/map/source_info.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MBGL_MAP_SOURCE_INFO -#define MBGL_MAP_SOURCE_INFO - -#include <mbgl/style/types.hpp> -#include <mbgl/util/constants.hpp> - -#include <array> -#include <vector> -#include <string> -#include <cstdint> - -namespace mbgl { - -class TileID; - -class SourceInfo { -public: - std::vector<std::string> tiles; - uint16_t minZoom = 0; - uint16_t maxZoom = 22; - std::string attribution; - std::array<float, 3> center = { { 0, 0, 0 } }; - std::array<float, 4> bounds = { { -180, -90, 180, 90 } }; -}; - -} // namespace mbgl - -#endif // MBGL_MAP_SOURCE_INFO diff --git a/src/mbgl/map/tile.cpp b/src/mbgl/map/tile.cpp deleted file mode 100644 index 408cdfaec5..0000000000 --- a/src/mbgl/map/tile.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include <mbgl/map/tile.hpp> - -using namespace mbgl; diff --git a/src/mbgl/map/tile.hpp b/src/mbgl/map/tile.hpp deleted file mode 100644 index 8b9030f1bd..0000000000 --- a/src/mbgl/map/tile.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MBGL_MAP_TILE -#define MBGL_MAP_TILE - -#include <mbgl/util/mat4.hpp> -#include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/ptr.hpp> -#include <mbgl/util/clip_id.hpp> -#include <mbgl/map/tile_id.hpp> - -namespace mbgl { - -class TileData; -struct box; - -class Tile : private util::noncopyable { -public: - explicit Tile(const TileID& id_) - : id(id_) {} - - const TileID id; - ClipID clip; - mat4 matrix; - util::ptr<TileData> data; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/tile_cache.cpp b/src/mbgl/map/tile_cache.cpp deleted file mode 100644 index 2d1a0da96c..0000000000 --- a/src/mbgl/map/tile_cache.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include <mbgl/map/tile_cache.hpp> - -#include <cassert> - -namespace mbgl { - -void TileCache::setSize(size_t size_) { - size = size_; - - while (orderedKeys.size() > size) { - auto key = orderedKeys.front(); - orderedKeys.pop_front(); - tiles.erase(key); - } - - assert(orderedKeys.size() <= size); - - tiles.reserve(size); -} - -void TileCache::add(uint64_t key, std::shared_ptr<TileData> data) { - - // insert new or query existing data - if (tiles.emplace(key, data).second) { - // remove existing data key - orderedKeys.remove(key); - } - - // (re-)insert data key as newest - orderedKeys.push_back(key); - - // purge oldest key/data if necessary - if (orderedKeys.size() > size) { - get(orderedKeys.front()); - } - - assert(orderedKeys.size() <= size); -}; - -std::shared_ptr<TileData> TileCache::get(uint64_t key) { - - std::shared_ptr<TileData> data; - - auto it = tiles.find(key); - if (it != tiles.end()) { - data = it->second; - tiles.erase(it); - orderedKeys.remove(key); - assert(data->isReady()); - } - - return data; -}; - -bool TileCache::has(uint64_t key) { - return tiles.find(key) != tiles.end(); -} - -void TileCache::clear() { - orderedKeys.clear(); - tiles.clear(); -} - -} // namespace mbgl diff --git a/src/mbgl/map/tile_cache.hpp b/src/mbgl/map/tile_cache.hpp deleted file mode 100644 index e39db0ffae..0000000000 --- a/src/mbgl/map/tile_cache.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MBGL_MAP_TILE_CACHE -#define MBGL_MAP_TILE_CACHE - -#include <mbgl/map/tile_data.hpp> - -#include <list> -#include <unordered_map> - -namespace mbgl { - -class TileCache { -public: - TileCache(size_t size_ = 0) : size(size_) {} - - void setSize(size_t); - size_t getSize() const { return size; }; - void add(uint64_t key, std::shared_ptr<TileData> data); - std::shared_ptr<TileData> get(uint64_t key); - bool has(uint64_t key); - void clear(); -private: - std::unordered_map<uint64_t, std::shared_ptr<TileData>> tiles; - std::list<uint64_t> orderedKeys; - - size_t size; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp deleted file mode 100644 index edfe4d7ada..0000000000 --- a/src/mbgl/map/tile_data.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include <mbgl/map/tile_data.hpp> -#include <mbgl/renderer/debug_bucket.hpp> -#include <mbgl/util/string.hpp> - -namespace mbgl { - -TileData::TileData(const TileID& id_) - : id(id_), - state(State::initial) { -} - -TileData::~TileData() = default; - -const char* TileData::StateToString(const State state) { - switch (state) { - case TileData::State::initial: return "initial"; - case TileData::State::invalid : return "invalid"; - case TileData::State::loading : return "loading"; - case TileData::State::loaded : return "loaded"; - case TileData::State::obsolete : return "obsolete"; - case TileData::State::parsed : return "parsed"; - case TileData::State::partial : return "partial"; - default: return "<unknown>"; - } -} - -void TileData::dumpDebugLogs() const { - Log::Info(Event::General, "TileData::id: %s", std::string(id).c_str()); - Log::Info(Event::General, "TileData::state: %s", TileData::StateToString(state)); -} - -} // namespace mbgl diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp deleted file mode 100644 index 90196f8a42..0000000000 --- a/src/mbgl/map/tile_data.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef MBGL_MAP_TILE_DATA -#define MBGL_MAP_TILE_DATA - -#include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/chrono.hpp> -#include <mbgl/util/optional.hpp> -#include <mbgl/map/tile_id.hpp> -#include <mbgl/renderer/bucket.hpp> -#include <mbgl/text/placement_config.hpp> - -#include <atomic> -#include <string> -#include <memory> -#include <functional> - -namespace mbgl { - -class StyleLayer; -class Worker; -class DebugBucket; - -class TileData : private util::noncopyable { -public: - // initial: - // Initial state, only used when the TileData object is created. - // - // invalid: - // FIXME: This state has a bit of overlap with 'initial' and 'obsolete'. - // - // We report TileData being 'invalid' on Source::hasTile if we don't have the - // TileData yet, then Source creates a request. This is misleading because - // the TileData object is not effectively on the 'invalid' state and will - // cause tiles on 'invalid' state to get reloaded. - // - // loading: - // A request to the FileSource was made for the actual tile data and TileData - // is waiting for it to arrive. - // - // loaded: - // The actual tile data has arrived and the tile can be parsed. - // - // partial: - // TileData is partially parsed, some buckets are still waiting for dependencies - // to arrive, but it is good for rendering. Partial tiles can also be re-parsed, - // but might remain in the same state if dependencies are still missing. - // - // parsed: - // TileData is fully parsed and its contents won't change from this point. This - // is the only state which is safe to cache this object. - // - // obsolete: - // The TileData can go to obsolete from any state, due to parsing or loading error, - // request cancellation or because the tile is no longer in use. - enum class State { - initial, - invalid, - loading, - loaded, - partial, - parsed, - obsolete - }; - - static const char* StateToString(State); - - // Tile data considered "Ready" can be used for rendering. Data in - // partial state is still waiting for network resources but can also - // be rendered, although layers will be missing. - inline static bool isReadyState(const State& state) { - return state == State::partial || state == State::parsed; - } - - TileData(const TileID&); - virtual ~TileData(); - - // Mark this tile as no longer needed and cancel any pending work. - virtual void cancel() = 0; - - virtual Bucket* getBucket(const StyleLayer&) = 0; - - virtual bool parsePending(std::function<void (std::exception_ptr)>) { return true; } - virtual void redoPlacement(PlacementConfig, const std::function<void()>&) {} - virtual void redoPlacement(const std::function<void()>&) {} - - bool isReady() const { - return isReadyState(state); - } - - State getState() const { - return state; - } - - void dumpDebugLogs() const; - - const TileID id; - optional<SystemTimePoint> modified; - optional<SystemTimePoint> expires; - - // Contains the tile ID string for painting debug information. - std::unique_ptr<DebugBucket> debugBucket; - -protected: - std::atomic<State> state; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/tile_id.hpp b/src/mbgl/map/tile_id.hpp index dddbce3bb7..a193b63392 100644 --- a/src/mbgl/map/tile_id.hpp +++ b/src/mbgl/map/tile_id.hpp @@ -6,6 +6,7 @@ #include <string> #include <functional> #include <forward_list> +#include <limits> namespace mbgl { @@ -25,12 +26,6 @@ public: return ((std::pow(2, z) * y + x) * 32) + z; } - struct Hash { - std::size_t operator()(const TileID& id) const { - return std::hash<uint64_t>()(id.to_uint64()); - } - }; - inline bool operator==(const TileID& rhs) const { return w == rhs.w && z == rhs.z && x == rhs.x && y == rhs.y; } @@ -48,12 +43,24 @@ public: TileID parent(int8_t z, int8_t sourceMaxZoom) const; TileID normalized() const; - std::forward_list<TileID> children(int8_t sourceMaxZoom) const; + std::forward_list<TileID> + children(int8_t sourceMaxZoom = std::numeric_limits<int8_t>::max()) const; bool isChildOf(const TileID&) const; operator std::string() const; - }; } // namespace mbgl +namespace std { +template <> +struct hash<mbgl::TileID> { + typedef mbgl::TileID argument_type; + typedef std::size_t result_type; + + result_type operator()(const mbgl::TileID& id) const { + return std::hash<uint64_t>()(id.to_uint64()); + } +}; +} // namespace std + #endif diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp deleted file mode 100644 index edbd392057..0000000000 --- a/src/mbgl/map/tile_worker.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include <mbgl/text/collision_tile.hpp> -#include <mbgl/map/tile_worker.hpp> -#include <mbgl/map/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)); - } -} diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp deleted file mode 100644 index bcd8e59bf9..0000000000 --- a/src/mbgl/map/tile_worker.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef MBGL_MAP_TILE_WORKER -#define MBGL_MAP_TILE_WORKER - -#include <mapbox/variant.hpp> - -#include <mbgl/map/mode.hpp> -#include <mbgl/map/tile_data.hpp> -#include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/ptr.hpp> -#include <mbgl/text/placement_config.hpp> - -#include <string> -#include <memory> -#include <mutex> -#include <list> -#include <unordered_map> - -namespace mbgl { - -class CollisionTile; -class GeometryTile; -class SpriteStore; -class GlyphAtlas; -class GlyphStore; -class Bucket; -class StyleLayer; -class SymbolLayer; - -// We're using this class to shuttle the resulting buckets from the worker thread to the MapContext -// thread. This class is movable-only because the vector contains movable-only value elements. -class TileParseResultBuckets { -public: - TileData::State state = TileData::State::invalid; - std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets; -}; - -using TileParseResult = mapbox::util::variant< - TileParseResultBuckets, // success - std::exception_ptr>; // error - -class TileWorker : public util::noncopyable { -public: - TileWorker(TileID, - std::string sourceID, - SpriteStore&, - GlyphAtlas&, - GlyphStore&, - const std::atomic<TileData::State>&, - const MapMode); - ~TileWorker(); - - TileParseResult parseAllLayers(std::vector<std::unique_ptr<StyleLayer>>, - std::unique_ptr<const GeometryTile> geometryTile, - PlacementConfig); - - TileParseResult parsePendingLayers(PlacementConfig); - - void redoPlacement(const std::unordered_map<std::string, std::unique_ptr<Bucket>>*, - PlacementConfig); - -private: - void parseLayer(const StyleLayer*, const GeometryTile&); - void insertBucket(const std::string& name, std::unique_ptr<Bucket>); - void placeLayers(PlacementConfig); - - const TileID id; - const std::string sourceID; - - SpriteStore& spriteStore; - GlyphAtlas& glyphAtlas; - GlyphStore& glyphStore; - const std::atomic<TileData::State>& state; - const MapMode mode; - - bool partialParse = false; - - std::vector<std::unique_ptr<StyleLayer>> layers; - - // Contains buckets that we couldn't parse so far due to missing resources. - // They will be attempted on subsequent parses. - std::list<std::pair<const SymbolLayer*, std::unique_ptr<Bucket>>> pending; - - // Contains buckets that have been parsed, but still need placement. - // They will be placed when all buckets have been parsed. - std::unordered_map<std::string, std::unique_ptr<Bucket>> placementPending; - - // Temporary holder - TileParseResultBuckets result; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 009534fc8b..087defabda 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -1,7 +1,6 @@ #include <mbgl/map/transform_state.hpp> #include <mbgl/map/tile_id.hpp> #include <mbgl/util/constants.hpp> -#include <mbgl/util/box.hpp> #include <mbgl/util/tile_coordinate.hpp> #include <mbgl/util/interpolate.hpp> #include <mbgl/util/math.hpp> @@ -54,18 +53,6 @@ void TransformState::getProjMatrix(mat4& projMatrix) const { pixel_y() - getHeight() / 2.0f, 0); } -box TransformState::cornersToBox(uint32_t z) const { - double w = width; - double h = height; - box b( - pointToCoordinate({ 0, 0 }).zoomTo(z), - pointToCoordinate({ w, 0 }).zoomTo(z), - pointToCoordinate({ w, h }).zoomTo(z), - pointToCoordinate({ 0, h }).zoomTo(z)); - return b; -} - - #pragma mark - Dimensions uint16_t TransformState::getWidth() const { diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index dfcc1ed1a0..0fb1f2304b 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -15,8 +15,7 @@ namespace mbgl { class TileID; -struct box; -struct TileCoordinate; +class TileCoordinate; class TransformState { friend class Transform; @@ -27,7 +26,6 @@ public: // Matrix void matrixFor(mat4& matrix, const TileID& id, const int8_t z) const; void getProjMatrix(mat4& matrix) const; - box cornersToBox(uint32_t z) const; // Dimensions uint16_t getWidth() const; diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp deleted file mode 100644 index 17746a26a1..0000000000 --- a/src/mbgl/map/vector_tile.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include <mbgl/map/vector_tile.hpp> -#include <mbgl/map/source.hpp> -#include <mbgl/storage/resource.hpp> -#include <mbgl/storage/response.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/util/thread_context.hpp> -#include <mbgl/util/url.hpp> - -#include <utility> - -namespace mbgl { - -Value parseValue(pbf data) { - while (data.next()) - { - switch (data.tag) - { - case 1: // string_value - return data.string(); - case 2: // float_value - return static_cast<double>(data.float32()); - case 3: // double_value - return data.float64(); - case 4: // int_value - return data.varint<int64_t>(); - case 5: // uint_value - return data.varint<uint64_t>(); - case 6: // sint_value - return data.svarint<int64_t>(); - case 7: // bool_value - return data.boolean(); - default: - data.skip(); - break; - } - } - return false; -} - -VectorTileFeature::VectorTileFeature(pbf feature_pbf, const VectorTileLayer& layer_) - : layer(layer_) { - while (feature_pbf.next()) { - if (feature_pbf.tag == 1) { // id - id = feature_pbf.varint<uint64_t>(); - } else if (feature_pbf.tag == 2) { // tags - tags_pbf = feature_pbf.message(); - } else if (feature_pbf.tag == 3) { // type - type = (FeatureType)feature_pbf.varint(); - } else if (feature_pbf.tag == 4) { // geometry - geometry_pbf = feature_pbf.message(); - } else { - feature_pbf.skip(); - } - } -} - -optional<Value> VectorTileFeature::getValue(const std::string& key) const { - auto keyIter = layer.keys.find(key); - if (keyIter == layer.keys.end()) { - return optional<Value>(); - } - - pbf tags = tags_pbf; - while (tags) { - uint32_t tag_key = tags.varint(); - - if (layer.keys.size() <= tag_key) { - throw std::runtime_error("feature referenced out of range key"); - } - - if (!tags) { - throw std::runtime_error("uneven number of feature tag ids"); - } - - uint32_t tag_val = tags.varint(); - if (layer.values.size() <= tag_val) { - throw std::runtime_error("feature referenced out of range value"); - } - - if (tag_key == keyIter->second) { - return layer.values[tag_val]; - } - } - - return optional<Value>(); -} - -GeometryCollection VectorTileFeature::getGeometries() const { - pbf data(geometry_pbf); - uint8_t cmd = 1; - uint32_t length = 0; - int32_t x = 0; - int32_t y = 0; - - GeometryCollection lines; - - lines.emplace_back(); - std::vector<Coordinate>* line = &lines.back(); - - while (data.data < data.end) { - if (length == 0) { - uint32_t cmd_length = data.varint(); - cmd = cmd_length & 0x7; - length = cmd_length >> 3; - } - - --length; - - if (cmd == 1 || cmd == 2) { - x += data.svarint(); - y += data.svarint(); - - if (cmd == 1 && !line->empty()) { // moveTo - lines.emplace_back(); - line = &lines.back(); - } - - line->emplace_back(x, y); - - } else if (cmd == 7) { // closePolygon - if (!line->empty()) { - line->push_back((*line)[0]); - } - - } else { - throw std::runtime_error("unknown command"); - } - } - - return lines; -} - -uint32_t VectorTileFeature::getExtent() const { - return layer.extent; -} - -VectorTile::VectorTile(std::shared_ptr<const std::string> data_) - : data(std::move(data_)) { -} - -util::ptr<GeometryTileLayer> VectorTile::getLayer(const std::string& name) const { - if (!parsed) { - parsed = true; - pbf tile_pbf(reinterpret_cast<const unsigned char *>(data->c_str()), data->size()); - while (tile_pbf.next()) { - if (tile_pbf.tag == 3) { // layer - util::ptr<VectorTileLayer> layer = std::make_shared<VectorTileLayer>(tile_pbf.message()); - layers.emplace(layer->name, layer); - } else { - tile_pbf.skip(); - } - } - } - - auto layer_it = layers.find(name); - if (layer_it != layers.end()) { - return layer_it->second; - } - - return nullptr; -} - -VectorTileLayer::VectorTileLayer(pbf layer_pbf) { - while (layer_pbf.next()) { - if (layer_pbf.tag == 1) { // name - name = layer_pbf.string(); - } else if (layer_pbf.tag == 2) { // feature - features.push_back(layer_pbf.message()); - } else if (layer_pbf.tag == 3) { // keys - keys.emplace(layer_pbf.string(), keys.size()); - } else if (layer_pbf.tag == 4) { // values - values.emplace_back(parseValue(layer_pbf.message())); - } else if (layer_pbf.tag == 5) { // extent - extent = layer_pbf.varint(); - } else { - layer_pbf.skip(); - } - } -} - -util::ptr<const GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const { - return std::make_shared<VectorTileFeature>(features.at(i), *this); -} - -VectorTileMonitor::VectorTileMonitor(const TileID& tileID_, float pixelRatio_, const std::string& urlTemplate_) - : tileID(tileID_), - pixelRatio(pixelRatio_), - urlTemplate(urlTemplate_) { -} - -std::unique_ptr<FileRequest> VectorTileMonitor::monitorTile(const GeometryTileMonitor::Callback& callback) { - const Resource resource = Resource::tile(urlTemplate, pixelRatio, tileID.x, tileID.y, tileID.sourceZ); - return util::ThreadContext::getFileSource()->request(resource, [callback, this](Response res) { - if (res.notModified) { - // We got the same data again. Abort early. - return; - } - - if (res.error) { - if (res.error->reason == Response::Error::Reason::NotFound) { - callback(nullptr, nullptr, res.modified, res.expires); - return; - } else { - callback(std::make_exception_ptr(std::runtime_error(res.error->message)), nullptr, res.modified, res.expires); - return; - } - } - - callback(nullptr, std::make_unique<VectorTile>(res.data), res.modified, res.expires); - }); -} - -} // namespace mbgl diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/map/vector_tile.hpp deleted file mode 100644 index 8550b1c55a..0000000000 --- a/src/mbgl/map/vector_tile.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef MBGL_MAP_VECTOR_TILE -#define MBGL_MAP_VECTOR_TILE - -#include <mbgl/map/geometry_tile.hpp> -#include <mbgl/map/tile_id.hpp> -#include <mbgl/util/pbf.hpp> - -#include <map> - -namespace mbgl { - -class VectorTileLayer; - -class VectorTileFeature : public GeometryTileFeature { -public: - VectorTileFeature(pbf, const VectorTileLayer&); - - FeatureType getType() const override { return type; } - optional<Value> getValue(const std::string&) const override; - GeometryCollection getGeometries() const override; - uint32_t getExtent() const override; - -private: - const VectorTileLayer& layer; - uint64_t id = 0; - FeatureType type = FeatureType::Unknown; - pbf tags_pbf; - pbf geometry_pbf; -}; - -class VectorTileLayer : public GeometryTileLayer { -public: - VectorTileLayer(pbf); - - std::size_t featureCount() const override { return features.size(); } - util::ptr<const GeometryTileFeature> getFeature(std::size_t) const override; - -private: - friend class VectorTile; - friend class VectorTileFeature; - - std::string name; - uint32_t extent = 4096; - std::map<std::string, uint32_t> keys; - std::vector<Value> values; - std::vector<pbf> features; -}; - -class VectorTile : public GeometryTile { -public: - VectorTile(std::shared_ptr<const std::string> data); - - util::ptr<GeometryTileLayer> getLayer(const std::string&) const override; - -private: - std::shared_ptr<const std::string> data; - mutable bool parsed = false; - mutable std::map<std::string, util::ptr<GeometryTileLayer>> layers; -}; - -class TileID; - -class VectorTileMonitor : public GeometryTileMonitor { -public: - VectorTileMonitor(const TileID&, float pixelRatio, const std::string& urlTemplate); - - std::unique_ptr<FileRequest> monitorTile(const GeometryTileMonitor::Callback&) override; - -private: - TileID tileID; - float pixelRatio; - std::string urlTemplate; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp deleted file mode 100644 index 27172a3e63..0000000000 --- a/src/mbgl/map/vector_tile_data.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include <mbgl/map/vector_tile_data.hpp> -#include <mbgl/map/geometry_tile.hpp> -#include <mbgl/style/style_layer.hpp> -#include <mbgl/util/worker.hpp> -#include <mbgl/util/work_request.hpp> -#include <mbgl/style/style.hpp> -#include <mbgl/storage/file_source.hpp> - -namespace mbgl { - -VectorTileData::VectorTileData(const TileID& id_, - std::unique_ptr<GeometryTileMonitor> monitor_, - std::string sourceID, - Style& style_, - const MapMode mode_, - const std::function<void(std::exception_ptr)>& callback) - : TileData(id_), - style(style_), - worker(style_.workers), - tileWorker(id_, - sourceID, - *style_.spriteStore, - *style_.glyphAtlas, - *style_.glyphStore, - state, - mode_), - monitor(std::move(monitor_)) -{ - state = State::loading; - tileRequest = monitor->monitorTile([callback, this](std::exception_ptr err, - std::unique_ptr<GeometryTile> tile, - optional<SystemTimePoint> modified_, - optional<SystemTimePoint> expires_) { - if (err) { - callback(err); - return; - } - - modified = modified_; - expires = expires_; - - if (!tile) { - // This is a 404 response. We're treating these as empty tiles. - workRequest.reset(); - state = State::parsed; - buckets.clear(); - callback(err); - return; - } - - if (state == State::loading) { - state = State::loaded; - } else if (isReady()) { - state = State::partial; - } - - // Kick off a fresh parse of this tile. This happens when the tile is new, or - // when tile data changed. Replacing the workdRequest will cancel a pending work - // request in case there is one. - workRequest.reset(); - workRequest = worker.parseGeometryTile(tileWorker, style.getLayers(), std::move(tile), targetConfig, [callback, this, config = targetConfig] (TileParseResult result) { - workRequest.reset(); - if (state == State::obsolete) { - return; - } - - std::exception_ptr error; - if (result.is<TileParseResultBuckets>()) { - auto& resultBuckets = result.get<TileParseResultBuckets>(); - state = resultBuckets.state; - - // Persist the configuration we just placed so that we can later check whether we need to - // place again in case the configuration has changed. - placedConfig = config; - - // Move over all buckets we received in this parse request, potentially overwriting - // existing buckets in case we got a refresh parse. - buckets = std::move(resultBuckets.buckets); - - } else { - error = result.get<std::exception_ptr>(); - state = State::obsolete; - } - - callback(error); - }); - }); -} - -VectorTileData::~VectorTileData() { - cancel(); -} - -bool VectorTileData::parsePending(std::function<void(std::exception_ptr)> callback) { - if (workRequest) { - // There's already parsing or placement going on. - return false; - } - - workRequest.reset(); - workRequest = worker.parsePendingGeometryTileLayers(tileWorker, targetConfig, [this, callback, config = targetConfig] (TileParseResult result) { - workRequest.reset(); - if (state == State::obsolete) { - return; - } - - std::exception_ptr error; - if (result.is<TileParseResultBuckets>()) { - auto& resultBuckets = result.get<TileParseResultBuckets>(); - state = resultBuckets.state; - - // Move over all buckets we received in this parse request, potentially overwriting - // existing buckets in case we got a refresh parse. - for (auto& bucket : resultBuckets.buckets) { - buckets[bucket.first] = std::move(bucket.second); - } - - // Persist the configuration we just placed so that we can later check whether we need to - // place again in case the configuration has changed. - placedConfig = config; - - } else { - error = result.get<std::exception_ptr>(); - state = State::obsolete; - } - - callback(error); - }); - - return true; -} - -Bucket* VectorTileData::getBucket(const StyleLayer& layer) { - const auto it = buckets.find(layer.bucketName()); - if (it == buckets.end()) { - return nullptr; - } - - assert(it->second); - return it->second.get(); -} - -void VectorTileData::redoPlacement(const PlacementConfig newConfig, const std::function<void()>& callback) { - if (newConfig != placedConfig) { - targetConfig = newConfig; - - redoPlacement(callback); - } -} - -void VectorTileData::redoPlacement(const std::function<void()>& callback) { - // Don't start a new placement request when the current one hasn't completed yet, or when - // we are parsing buckets. - if (workRequest) return; - - workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, callback, config = targetConfig] { - workRequest.reset(); - - // Persist the configuration we just placed so that we can later check whether we need to - // place again in case the configuration has changed. - placedConfig = config; - - for (auto& bucket : buckets) { - bucket.second->swapRenderData(); - } - - // The target configuration could have changed since we started placement. In this case, - // we're starting another placement run. - if (placedConfig != targetConfig) { - redoPlacement(callback); - } else { - callback(); - } - }); -} - -void VectorTileData::cancel() { - state = State::obsolete; - tileRequest.reset(); - workRequest.reset(); -} - -} // namespace mbgl diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp deleted file mode 100644 index b61b2a25a0..0000000000 --- a/src/mbgl/map/vector_tile_data.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef MBGL_MAP_VECTOR_TILE_DATA -#define MBGL_MAP_VECTOR_TILE_DATA - -#include <mbgl/map/tile_data.hpp> -#include <mbgl/map/tile_worker.hpp> -#include <mbgl/text/placement_config.hpp> - -#include <atomic> -#include <memory> -#include <unordered_map> - -namespace mbgl { - -class Style; -class WorkRequest; -class FileRequest; -class GeometryTileMonitor; - -class VectorTileData : public TileData { -public: - VectorTileData(const TileID&, - std::unique_ptr<GeometryTileMonitor> monitor, - std::string sourceID, - Style&, - const MapMode, - const std::function<void(std::exception_ptr)>& callback); - - ~VectorTileData(); - - Bucket* getBucket(const StyleLayer&) override; - - bool parsePending(std::function<void(std::exception_ptr)> callback) override; - - void redoPlacement(PlacementConfig config, const std::function<void()>&) override; - void redoPlacement(const std::function<void()>&) override; - - void cancel() override; - -private: - Style& style; - Worker& worker; - TileWorker tileWorker; - - std::unique_ptr<GeometryTileMonitor> monitor; - std::unique_ptr<FileRequest> tileRequest; - std::unique_ptr<WorkRequest> workRequest; - - // Contains all the Bucket objects for the tile. Buckets are render - // objects and they get added by tile parsing operations. - std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets; - - // Stores the placement configuration of the text that is currently placed on the screen. - PlacementConfig placedConfig; - - // Stores the placement configuration of how the text should be placed. This isn't necessarily - // the one that is being displayed. - PlacementConfig targetConfig; -}; - -} // namespace mbgl - -#endif |