diff --git a/CHANGELOG.md b/CHANGELOG.md index d13cb009bf6..748d8838cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ This property allows to re-open the offline database in read-only mode and thus improves the performance for the set-ups that do not require the offline database modifications. +- [core] Add runtime API for setting tile prefetch delta for a Source ([#16179](https://github.com/mapbox/mapbox-gl-native/pull/16179)) + + The new `Source::setPrefetchZoomDelta(optional)` method allows overriding default tile prefetch setting that is defined by the Map instance. + ## maps-v1.0.1 (2020.01-release-unicorn) ### 🐞 Bug fixes diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp index c3c0609a9f8..59afd6916e9 100644 --- a/include/mbgl/style/source.hpp +++ b/include/mbgl/style/source.hpp @@ -73,6 +73,8 @@ class Source : public mbgl::util::noncopyable { SourceObserver* observer = nullptr; virtual void loadDescription(FileSource&) = 0; + void setPrefetchZoomDelta(optional delta) noexcept; + optional getPrefetchZoomDelta() const noexcept; void dumpDebugLogs() const; virtual bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const = 0; @@ -85,6 +87,9 @@ class Source : public mbgl::util::noncopyable { mapbox::base::TypeWrapper peer; virtual mapbox::base::WeakPtr makeWeakPtr() = 0; + +protected: + virtual Mutable createMutable() const noexcept = 0; }; } // namespace style diff --git a/include/mbgl/style/sources/custom_geometry_source.hpp b/include/mbgl/style/sources/custom_geometry_source.hpp index ff045056993..504ec42ea8a 100644 --- a/include/mbgl/style/sources/custom_geometry_source.hpp +++ b/include/mbgl/style/sources/custom_geometry_source.hpp @@ -50,6 +50,10 @@ class CustomGeometrySource final : public Source { mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } + +protected: + Mutable createMutable() const noexcept final; + private: std::shared_ptr threadPool; std::unique_ptr> loader; diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index 750d29627d2..4bd250b8957 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -81,6 +81,9 @@ class GeoJSONSource final : public Source { return weakFactory.makeWeakPtr(); } +protected: + Mutable createMutable() const noexcept final; + private: optional url; std::unique_ptr req; diff --git a/include/mbgl/style/sources/image_source.hpp b/include/mbgl/style/sources/image_source.hpp index 699a3c6494c..d2b7c37bdfd 100644 --- a/include/mbgl/style/sources/image_source.hpp +++ b/include/mbgl/style/sources/image_source.hpp @@ -33,6 +33,10 @@ class ImageSource final : public Source { mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } + +protected: + Mutable createMutable() const noexcept final; + private: optional url; std::unique_ptr req; diff --git a/include/mbgl/style/sources/raster_source.hpp b/include/mbgl/style/sources/raster_source.hpp index 00a3b788c2a..e06c3404e9d 100644 --- a/include/mbgl/style/sources/raster_source.hpp +++ b/include/mbgl/style/sources/raster_source.hpp @@ -31,6 +31,9 @@ class RasterSource : public Source { return weakFactory.makeWeakPtr(); } +protected: + Mutable createMutable() const noexcept final; + private: const variant urlOrTileset; std::unique_ptr req; diff --git a/include/mbgl/style/sources/vector_source.hpp b/include/mbgl/style/sources/vector_source.hpp index 4165af0a61a..83fcae95d6c 100644 --- a/include/mbgl/style/sources/vector_source.hpp +++ b/include/mbgl/style/sources/vector_source.hpp @@ -30,6 +30,9 @@ class VectorSource final : public Source { return weakFactory.makeWeakPtr(); } +protected: + Mutable createMutable() const noexcept final; + private: const variant urlOrTileset; std::unique_ptr req; diff --git a/metrics/binary-size/macos-xcode11/metrics.json b/metrics/binary-size/macos-xcode11/metrics.json index dc74d1c455b..06a66871439 100644 --- a/metrics/binary-size/macos-xcode11/metrics.json +++ b/metrics/binary-size/macos-xcode11/metrics.json @@ -3,17 +3,17 @@ [ "mbgl-glfw", "/tmp/attach/install/macos-xcode11-release/bin/mbgl-glfw", - 5562556 + 5616056 ], [ "mbgl-offline", "/tmp/attach/install/macos-xcode11-release/bin/mbgl-offline", - 5427032 + 5484604 ], [ "mbgl-render", "/tmp/attach/install/macos-xcode11-release/bin/mbgl-render", - 5477244 + 5530720 ] ] -} +} \ No newline at end of file diff --git a/src/mbgl/annotation/annotation_source.cpp b/src/mbgl/annotation/annotation_source.cpp index 7a137f18812..318241a9145 100644 --- a/src/mbgl/annotation/annotation_source.cpp +++ b/src/mbgl/annotation/annotation_source.cpp @@ -14,6 +14,10 @@ AnnotationSource::Impl::Impl() : Source::Impl(SourceType::Annotations, AnnotationManager::SourceID) { } +const AnnotationSource::Impl& AnnotationSource::impl() const { + return static_cast(*baseImpl); +} + void AnnotationSource::loadDescription(FileSource&) { loaded = true; } @@ -26,4 +30,8 @@ bool AnnotationSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) return !std::strcmp(info->type, "line") || !std::strcmp(info->type, "symbol") || !std::strcmp(info->type, "fill"); } +Mutable AnnotationSource::createMutable() const noexcept { + return staticMutableCast(makeMutable(impl())); +} + } // namespace mbgl diff --git a/src/mbgl/annotation/annotation_source.hpp b/src/mbgl/annotation/annotation_source.hpp index 0379426b3ef..de432202a07 100644 --- a/src/mbgl/annotation/annotation_source.hpp +++ b/src/mbgl/annotation/annotation_source.hpp @@ -12,13 +12,15 @@ class AnnotationSource final : public style::Source { class Impl; const Impl& impl() const; +protected: + Mutable createMutable() const noexcept final; + private: void loadDescription(FileSource&) final; bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override; mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } - Mutable mutableImpl() const; mapbox::base::WeakPtrFactory weakFactory {this}; }; diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index e3acfcb3c0f..85665961d3a 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -28,19 +28,19 @@ void RenderAnnotationSource::update(Immutable baseImpl_, enabled = needsRendering; - tilePyramid.update(layers, - needsRendering, - needsRelayout, - parameters, - SourceType::Annotations, - util::tileSize, - // Zoom level 16 is typically sufficient for annotations. - // See https://github.com/mapbox/mapbox-gl-native/issues/10197 - { 0, 16 }, - optional {}, - [&] (const OverscaledTileID& tileID) { - return std::make_unique(tileID, parameters); - }); + tilePyramid.update( + layers, + needsRendering, + needsRelayout, + parameters, + SourceType::Annotations, + util::tileSize, + // Zoom level 16 is typically sufficient for annotations. + // See https://github.com/mapbox/mapbox-gl-native/issues/10197 + {0, 16}, + optional{}, + [&](const OverscaledTileID& tileID) { return std::make_unique(tileID, parameters); }, + baseImpl->getPrefetchZoomDelta()); } std::unordered_map> diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp index 6b81658370c..a54802b21b4 100644 --- a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp +++ b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp @@ -23,7 +23,14 @@ void RenderCustomGeometrySource::update(Immutable baseImpl_ const TileParameters& parameters) { if (baseImpl != baseImpl_) { std::swap(baseImpl, baseImpl_); - tilePyramid.clearAll(); + + // Clear tile pyramid only if updated source has different tile options, + // zoom range or initialization state for a custom tile loader. + auto newImpl = staticImmutableCast(baseImpl); + auto currentImpl = staticImmutableCast(baseImpl_); + if (*newImpl != *currentImpl) { + tilePyramid.clearAll(); + } } enabled = needsRendering; @@ -33,17 +40,20 @@ void RenderCustomGeometrySource::update(Immutable baseImpl_ return; } - tilePyramid.update(layers, - needsRendering, - needsRelayout, - parameters, - SourceType::CustomVector, - util::tileSize, - impl().getZoomRange(), - {}, - [&] (const OverscaledTileID& tileID) { - return std::make_unique(tileID, impl().id, parameters, impl().getTileOptions(), *tileLoader); - }); + tilePyramid.update( + layers, + needsRendering, + needsRelayout, + parameters, + SourceType::CustomVector, + util::tileSize, + impl().getZoomRange(), + {}, + [&](const OverscaledTileID& tileID) { + return std::make_unique( + tileID, impl().id, parameters, impl().getTileOptions(), *tileLoader); + }, + baseImpl->getPrefetchZoomDelta()); } } // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 94d171cf18b..45a91e3fa06 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -103,17 +103,19 @@ void RenderGeoJSONSource::update(Immutable baseImpl_, if (!data_) return; - tilePyramid.update(layers, - needsRendering, - needsRelayout, - parameters, - SourceType::GeoJSON, - util::tileSize, - impl().getZoomRange(), - optional{}, - [&, data_](const OverscaledTileID& tileID) { - return std::make_unique(tileID, impl().id, parameters, data_); - }); + tilePyramid.update( + layers, + needsRendering, + needsRelayout, + parameters, + SourceType::GeoJSON, + util::tileSize, + impl().getZoomRange(), + optional{}, + [&, data_](const OverscaledTileID& tileID) { + return std::make_unique(tileID, impl().id, parameters, data_); + }, + baseImpl->getPrefetchZoomDelta()); } mapbox::util::variant diff --git a/src/mbgl/renderer/sources/render_raster_dem_source.cpp b/src/mbgl/renderer/sources/render_raster_dem_source.cpp index fb6e3436709..953484f6c6c 100644 --- a/src/mbgl/renderer/sources/render_raster_dem_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_dem_source.cpp @@ -27,17 +27,17 @@ void RenderRasterDEMSource::updateInternal(const Tileset& tileset, const bool needsRendering, const bool needsRelayout, const TileParameters& parameters) { - tilePyramid.update(layers, - needsRendering, - needsRelayout, - parameters, - SourceType::RasterDEM, - impl().getTileSize(), - tileset.zoomRange, - tileset.bounds, - [&] (const OverscaledTileID& tileID) { - return std::make_unique(tileID, parameters, tileset); - }); + tilePyramid.update( + layers, + needsRendering, + needsRelayout, + parameters, + SourceType::RasterDEM, + impl().getTileSize(), + tileset.zoomRange, + tileset.bounds, + [&](const OverscaledTileID& tileID) { return std::make_unique(tileID, parameters, tileset); }, + baseImpl->getPrefetchZoomDelta()); algorithm::updateTileMasks(tilePyramid.getRenderedTiles()); } diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index 408f8a4e119..7ef7b26459f 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -25,17 +25,17 @@ void RenderRasterSource::updateInternal(const Tileset& tileset, const bool needsRendering, const bool needsRelayout, const TileParameters& parameters) { - tilePyramid.update(layers, - needsRendering, - needsRelayout, - parameters, - SourceType::Raster, - impl().getTileSize(), - tileset.zoomRange, - tileset.bounds, - [&] (const OverscaledTileID& tileID) { - return std::make_unique(tileID, parameters, tileset); - }); + tilePyramid.update( + layers, + needsRendering, + needsRelayout, + parameters, + SourceType::Raster, + impl().getTileSize(), + tileset.zoomRange, + tileset.bounds, + [&](const OverscaledTileID& tileID) { return std::make_unique(tileID, parameters, tileset); }, + baseImpl->getPrefetchZoomDelta()); algorithm::updateTileMasks(tilePyramid.getRenderedTiles()); } diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp index 6e4fdede10d..324599d45d3 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -21,17 +21,19 @@ void RenderVectorSource::updateInternal(const Tileset& tileset, const bool needsRendering, const bool needsRelayout, const TileParameters& parameters) { - tilePyramid.update(layers, - needsRendering, - needsRelayout, - parameters, - SourceType::Vector, - util::tileSize, - tileset.zoomRange, - tileset.bounds, - [&] (const OverscaledTileID& tileID) { - return std::make_unique(tileID, baseImpl->id, parameters, tileset); - }); + tilePyramid.update( + layers, + needsRendering, + needsRelayout, + parameters, + SourceType::Vector, + util::tileSize, + tileset.zoomRange, + tileset.bounds, + [&](const OverscaledTileID& tileID) { + return std::make_unique(tileID, baseImpl->id, parameters, tileset); + }, + baseImpl->getPrefetchZoomDelta()); } } // namespace mbgl diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 586d3b5a8ae..38d984bec4a 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -57,7 +57,8 @@ void TilePyramid::update(const std::vector>& l const uint16_t tileSize, const Range zoomRange, optional bounds, - std::function (const OverscaledTileID&)> createTile) { + std::function(const OverscaledTileID&)> createTile, + optional sourcePrefetchZoomDelta) { // If we need a relayout, abandon any cached tiles; they're now stale. if (needsRelayout) { cache.clear(); @@ -105,8 +106,10 @@ void TilePyramid::update(const std::vector>& l if (parameters.mode == MapMode::Continuous && type != style::SourceType::GeoJSON && type != style::SourceType::Annotations) { // Request lower zoom level tiles (if configured to do so) in an attempt // to show something on the screen faster at the cost of a little of bandwidth. - if (parameters.prefetchZoomDelta) { - panZoom = std::max(tileZoom - parameters.prefetchZoomDelta, zoomRange.min); + const uint8_t prefetchZoomDelta = + sourcePrefetchZoomDelta ? *sourcePrefetchZoomDelta : parameters.prefetchZoomDelta; + if (prefetchZoomDelta) { + panZoom = std::max(tileZoom - prefetchZoomDelta, zoomRange.min); } if (panZoom < idealZoom) { diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index 3b5cab5d6cc..5f2bfd1ea9c 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -41,7 +41,8 @@ class TilePyramid { uint16_t tileSize, Range zoomRange, optional bounds, - std::function (const OverscaledTileID&)> createTile); + std::function(const OverscaledTileID&)> createTile, + optional sourcePrefetchZoomDelta); const std::map>& getRenderedTiles() const { return renderedTiles; } Tile* getTile(const OverscaledTileID&); diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp index e7701b8beca..644a31dace6 100644 --- a/src/mbgl/style/source.cpp +++ b/src/mbgl/style/source.cpp @@ -31,6 +31,18 @@ void Source::setObserver(SourceObserver* observer_) { observer = observer_ ? observer_ : &nullObserver; } +void Source::setPrefetchZoomDelta(optional delta) noexcept { + if (getPrefetchZoomDelta() == delta) return; + auto newImpl = createMutable(); + newImpl->setPrefetchZoomDelta(std::move(delta)); + baseImpl = std::move(newImpl); + observer->onSourceChanged(*this); +} + +optional Source::getPrefetchZoomDelta() const noexcept { + return baseImpl->getPrefetchZoomDelta(); +} + void Source::dumpDebugLogs() const { Log::Info(Event::General, "Source::id: %s", getID().c_str()); Log::Info(Event::General, "Source::loaded: %d", loaded); diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp index 0683f847cb6..7f6f633eda5 100644 --- a/src/mbgl/style/source_impl.cpp +++ b/src/mbgl/style/source_impl.cpp @@ -8,5 +8,13 @@ Source::Impl::Impl(SourceType type_, std::string id_) id(std::move(id_)) { } +void Source::Impl::setPrefetchZoomDelta(optional delta) noexcept { + prefetchZoomDelta = std::move(delta); +} + +optional Source::Impl::getPrefetchZoomDelta() const noexcept { + return prefetchZoomDelta; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp index 42da97345a3..d2c5d54d10b 100644 --- a/src/mbgl/style/source_impl.hpp +++ b/src/mbgl/style/source_impl.hpp @@ -20,9 +20,12 @@ class Source::Impl { Impl& operator=(const Impl&) = delete; virtual optional getAttribution() const = 0; + void setPrefetchZoomDelta(optional delta) noexcept; + optional getPrefetchZoomDelta() const noexcept; const SourceType type; const std::string id; + optional prefetchZoomDelta; protected: Impl(SourceType, std::string); diff --git a/src/mbgl/style/sources/custom_geometry_source.cpp b/src/mbgl/style/sources/custom_geometry_source.cpp index 1076cbf4179..44401c1a8f3 100644 --- a/src/mbgl/style/sources/custom_geometry_source.cpp +++ b/src/mbgl/style/sources/custom_geometry_source.cpp @@ -14,11 +14,10 @@ namespace mbgl { namespace style { -CustomGeometrySource::CustomGeometrySource(std::string id, - const CustomGeometrySource::Options options) +CustomGeometrySource::CustomGeometrySource(std::string id, CustomGeometrySource::Options options) : Source(makeMutable(std::move(id), options)), - loader(std::make_unique>(Scheduler::GetBackground(), options.fetchTileFunction, options.cancelTileFunction)) { -} + loader(std::make_unique>( + Scheduler::GetBackground(), options.fetchTileFunction, options.cancelTileFunction)) {} CustomGeometrySource::~CustomGeometrySource() = default; @@ -27,7 +26,7 @@ const CustomGeometrySource::Impl& CustomGeometrySource::impl() const { } void CustomGeometrySource::loadDescription(FileSource&) { - baseImpl = makeMutable(impl(), loader->self()); + baseImpl = makeMutable(impl(), loader->self()); loaded = true; observer->onSourceLoaded(*this); } @@ -49,5 +48,9 @@ void CustomGeometrySource::invalidateRegion(const LatLngBounds& bounds) { loader->self().invoke(&CustomTileLoader::invalidateRegion, bounds, impl().getZoomRange()); } +Mutable CustomGeometrySource::createMutable() const noexcept { + return staticMutableCast(makeMutable(impl())); +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/sources/custom_geometry_source_impl.cpp b/src/mbgl/style/sources/custom_geometry_source_impl.cpp index 67d52bdc246..e456bd87191 100644 --- a/src/mbgl/style/sources/custom_geometry_source_impl.cpp +++ b/src/mbgl/style/sources/custom_geometry_source_impl.cpp @@ -4,27 +4,24 @@ namespace mbgl { namespace style { -CustomGeometrySource::Impl::Impl(std::string id_, - const CustomGeometrySource::Options options) +CustomGeometrySource::Impl::Impl(std::string id_, CustomGeometrySource::Options options) : Source::Impl(SourceType::CustomVector, std::move(id_)), - tileOptions(options.tileOptions), + tileOptions(makeMutable(options.tileOptions)), zoomRange(options.zoomRange), - loaderRef({}) { -} + loaderRef({}) {} CustomGeometrySource::Impl::Impl(const Impl& impl, ActorRef loaderRef_) - : Source::Impl(impl), - tileOptions(impl.tileOptions), - zoomRange(impl.zoomRange), - loaderRef(loaderRef_){ - + : Source::Impl(impl), tileOptions(impl.tileOptions), zoomRange(impl.zoomRange), loaderRef(loaderRef_) {} + +bool CustomGeometrySource::Impl::operator!=(const Impl& other) const noexcept { + return tileOptions != other.tileOptions || zoomRange != other.zoomRange || bool(loaderRef) != bool(other.loaderRef); } optional CustomGeometrySource::Impl::getAttribution() const { return {}; } -CustomGeometrySource::TileOptions CustomGeometrySource::Impl::getTileOptions() const { +Immutable CustomGeometrySource::Impl::getTileOptions() const { return tileOptions; } diff --git a/src/mbgl/style/sources/custom_geometry_source_impl.hpp b/src/mbgl/style/sources/custom_geometry_source_impl.hpp index ce7187202dc..04e301f1988 100644 --- a/src/mbgl/style/sources/custom_geometry_source_impl.hpp +++ b/src/mbgl/style/sources/custom_geometry_source_impl.hpp @@ -15,12 +15,13 @@ class CustomGeometrySource::Impl : public Source::Impl { optional getAttribution() const final; - CustomGeometrySource::TileOptions getTileOptions() const; + Immutable getTileOptions() const; Range getZoomRange() const; optional> getTileLoader() const; + bool operator!=(const Impl&) const noexcept; private: - CustomGeometrySource::TileOptions tileOptions; + Immutable tileOptions; Range zoomRange; optional> loaderRef; }; diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index 3afccf07f2f..2880b9b1315 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -120,5 +120,9 @@ bool GeoJSONSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) co return mbgl::underlying_type(Tile::Kind::Geometry) == mbgl::underlying_type(info->tileKind); } +Mutable GeoJSONSource::createMutable() const noexcept { + return staticMutableCast(makeMutable(impl())); +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/sources/image_source.cpp b/src/mbgl/style/sources/image_source.cpp index d55f7c9f09c..ec727a33bd1 100644 --- a/src/mbgl/style/sources/image_source.cpp +++ b/src/mbgl/style/sources/image_source.cpp @@ -87,5 +87,9 @@ bool ImageSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) cons return mbgl::underlying_type(Tile::Kind::Raster) == mbgl::underlying_type(info->tileKind); } +Mutable ImageSource::createMutable() const noexcept { + return staticMutableCast(makeMutable(impl())); +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp index f90306945ec..8c41da3a233 100644 --- a/src/mbgl/style/sources/raster_source.cpp +++ b/src/mbgl/style/sources/raster_source.cpp @@ -87,5 +87,9 @@ bool RasterSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) con return mbgl::underlying_type(Tile::Kind::Raster) == mbgl::underlying_type(info->tileKind); } +Mutable RasterSource::createMutable() const noexcept { + return staticMutableCast(makeMutable(impl())); +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp index 510106adb9b..cc2319b302c 100644 --- a/src/mbgl/style/sources/vector_source.cpp +++ b/src/mbgl/style/sources/vector_source.cpp @@ -91,5 +91,9 @@ bool VectorSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) con return mbgl::underlying_type(Tile::Kind::Geometry) == mbgl::underlying_type(info->tileKind); } +Mutable VectorSource::createMutable() const noexcept { + return staticMutableCast(makeMutable(impl())); +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/tile/custom_geometry_tile.cpp b/src/mbgl/tile/custom_geometry_tile.cpp index 7b1fc2e2d93..660dcf64d4e 100644 --- a/src/mbgl/tile/custom_geometry_tile.cpp +++ b/src/mbgl/tile/custom_geometry_tile.cpp @@ -13,17 +13,16 @@ namespace mbgl { CustomGeometryTile::CustomGeometryTile(const OverscaledTileID& overscaledTileID, - std::string sourceID_, - const TileParameters& parameters, - const style::CustomGeometrySource::TileOptions options_, - ActorRef loader_) + std::string sourceID_, + const TileParameters& parameters, + Immutable options_, + ActorRef loader_) : GeometryTile(overscaledTileID, sourceID_, parameters), - necessity(TileNecessity::Optional), - options(options_), - loader(std::move(loader_)), - mailbox(std::make_shared(*Scheduler::GetCurrent())), - actorRef(*this, mailbox) { -} + necessity(TileNecessity::Optional), + options(std::move(options_)), + loader(std::move(loader_)), + mailbox(std::make_shared(*Scheduler::GetCurrent())), + actorRef(*this, mailbox) {} CustomGeometryTile::~CustomGeometryTile() { loader.invoke(&style::CustomTileLoader::removeTile, id); @@ -33,15 +32,16 @@ void CustomGeometryTile::setTileData(const GeoJSON& geoJSON) { auto featureData = mapbox::feature::feature_collection(); if (geoJSON.is() && !geoJSON.get().empty()) { - const double scale = util::EXTENT / options.tileSize; + const double scale = util::EXTENT / options->tileSize; mapbox::geojsonvt::TileOptions vtOptions; vtOptions.extent = util::EXTENT; - vtOptions.buffer = ::round(scale * options.buffer); - vtOptions.tolerance = scale * options.tolerance; - featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON, - id.canonical.z, id.canonical.x, id.canonical.y, - vtOptions, options.wrap, options.clip).features; + vtOptions.buffer = ::round(scale * options->buffer); + vtOptions.tolerance = scale * options->tolerance; + featureData = + mapbox::geojsonvt::geoJSONToTile( + geoJSON, id.canonical.z, id.canonical.x, id.canonical.y, vtOptions, options->wrap, options->clip) + .features; } setData(std::make_unique(std::move(featureData))); } diff --git a/src/mbgl/tile/custom_geometry_tile.hpp b/src/mbgl/tile/custom_geometry_tile.hpp index 1df44e6b2af..3f8cc272790 100644 --- a/src/mbgl/tile/custom_geometry_tile.hpp +++ b/src/mbgl/tile/custom_geometry_tile.hpp @@ -17,10 +17,10 @@ class CustomTileLoader; class CustomGeometryTile: public GeometryTile { public: CustomGeometryTile(const OverscaledTileID&, - std::string sourceID, - const TileParameters&, - const style::CustomGeometrySource::TileOptions, - ActorRef loader); + std::string sourceID, + const TileParameters&, + Immutable, + ActorRef loader); ~CustomGeometryTile() override; void setTileData(const GeoJSON& data); @@ -35,7 +35,7 @@ class CustomGeometryTile: public GeometryTile { private: bool stale = true; TileNecessity necessity; - const style::CustomGeometrySource::TileOptions options; + Immutable options; ActorRef loader; std::shared_ptr mailbox; ActorRef actorRef; diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 89be4ad73ec..54dbccdafc1 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -1119,3 +1121,133 @@ TEST(Map, NoHangOnMissingImage) { // The test passes if the following call does not hang. test.frontend.render(test.map); } + +TEST(Map, PrefetchDeltaOverride) { + MapTest<> test{1, MapMode::Continuous}; + + test.map.getStyle().loadJSON( + R"STYLE({ + "layers": [{ + "id": "vector", + "type": "fill", + "source": "vector", + "minzoom": 0, + "maxzoom": 24 + }, + { + "id": "custom", + "type": "fill", + "source": "custom", + "minzoom": 0, + "maxzoom": 24 + }] + })STYLE"); + + // Vector source + auto vectorSource = std::make_unique("vector", Tileset{{"a/{z}/{x}/{y}"}}); + vectorSource->setPrefetchZoomDelta(0); + test.map.getStyle().addSource(std::move(vectorSource)); + + unsigned requestedTiles = 0u; + test.fileSource->tileResponse = [&](const Resource&) { + ++requestedTiles; + Response res; + res.noContent = true; + return res; + }; + + // Custom source + CustomGeometrySource::Options options; + options.cancelTileFunction = [](const CanonicalTileID&) {}; + options.fetchTileFunction = [&requestedTiles, &test](const CanonicalTileID& tileID) { + ++requestedTiles; + auto* customSrc = static_cast(test.map.getStyle().getSource("custom")); + if (customSrc) { + customSrc->setTileData(tileID, {}); + } + }; + auto customSource = std::make_unique("custom", std::move(options)); + customSource->setPrefetchZoomDelta(0); + test.map.getStyle().addSource(std::move(customSource)); + + test.map.jumpTo(CameraOptions().withZoom(double(16))); + test.observer.didFinishLoadingMapCallback = [&] { test.runLoop.stop(); }; + test.runLoop.run(); + // 2 sources x 4 tiles + EXPECT_EQ(8, requestedTiles); + + requestedTiles = 0u; + + // Should request z12 tiles when delta is set back to default, that is 4. + test.observer.didFinishRenderingFrameCallback = [&](MapObserver::RenderFrameStatus status) { + if (status.mode == MapObserver::RenderMode::Full) { + test.runLoop.stop(); + } + }; + + test.map.getStyle().getSource("vector")->setPrefetchZoomDelta(nullopt); + test.map.getStyle().getSource("custom")->setPrefetchZoomDelta(nullopt); + test.runLoop.run(); + + // Each source requests 4 additional parent tiles. + EXPECT_EQ(8, requestedTiles); +} + +// Test that custom source's tile pyramid is reset +// if there is a significant change. +TEST(Map, PrefetchDeltaOverrideCustomSource) { + MapTest<> test{1, MapMode::Continuous}; + + test.map.getStyle().loadJSON( + R"STYLE({ + "layers": [{ + "id": "custom", + "type": "fill", + "source": "custom", + "source-layer": "a", + "minzoom": 0, + "maxzoom": 24 + }] + })STYLE"); + + unsigned requestedTiles = 0u; + + auto makeCustomSource = [&requestedTiles, &test] { + CustomGeometrySource::Options options; + options.cancelTileFunction = [](const CanonicalTileID&) {}; + options.fetchTileFunction = [&requestedTiles, &test](const CanonicalTileID& tileID) { + ++requestedTiles; + auto* source = static_cast(test.map.getStyle().getSource("custom")); + if (source) { + source->setTileData(tileID, {}); + } + }; + return std::make_unique("custom", std::move(options)); + }; + + auto customSource = makeCustomSource(); + customSource->setPrefetchZoomDelta(0); + test.map.getStyle().addSource(std::move(customSource)); + + test.map.jumpTo(CameraOptions().withZoom(double(16))); + test.observer.didFinishLoadingMapCallback = [&] { test.runLoop.stop(); }; + test.runLoop.run(); + EXPECT_EQ(4, requestedTiles); + requestedTiles = 0u; + + test.observer.didFinishRenderingFrameCallback = [&](MapObserver::RenderFrameStatus status) { + if (status.mode == MapObserver::RenderMode::Full) { + test.runLoop.stop(); + } + }; + + auto layer = test.map.getStyle().removeLayer("custom"); + std::move(test.map.getStyle().removeSource("custom")); + test.map.getStyle().addLayer(std::move(layer)); + test.map.getStyle().addSource(makeCustomSource()); + test.runLoop.run(); + + // Source was significantly mutated, therefore, tile pyramid would be cleared + // and current zoom level + parent tiles would be re-requested. + EXPECT_EQ(8, requestedTiles); +} diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp index 0286aaaec3c..dbc67681e91 100644 --- a/test/style/source.test.cpp +++ b/test/style/source.test.cpp @@ -765,15 +765,17 @@ class FakeTileSource : public RenderTileSetSource { const bool needsRendering, const bool needsRelayout, const TileParameters& parameters) override { - tilePyramid.update(layers, - needsRendering, - needsRelayout, - parameters, - SourceType::Vector, - util::tileSize, - tileset.zoomRange, - tileset.bounds, - [&](const OverscaledTileID& tileID) { return std::make_unique(*this, tileID); }); + tilePyramid.update( + layers, + needsRendering, + needsRelayout, + parameters, + SourceType::Vector, + util::tileSize, + tileset.zoomRange, + tileset.bounds, + [&](const OverscaledTileID& tileID) { return std::make_unique(*this, tileID); }, + baseImpl->getPrefetchZoomDelta()); } const optional& getTileset() const override { diff --git a/test/tile/custom_geometry_tile.test.cpp b/test/tile/custom_geometry_tile.test.cpp index f3d11ab8985..6e8a7e69819 100644 --- a/test/tile/custom_geometry_tile.test.cpp +++ b/test/tile/custom_geometry_tile.test.cpp @@ -61,8 +61,11 @@ TEST(CustomGeometryTile, InvokeFetchTile) { auto mb =std::make_shared(*Scheduler::GetCurrent()); ActorRef loaderActor(loader, mb); - CustomGeometryTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, CustomGeometrySource::TileOptions(), - loaderActor); + CustomGeometryTile tile(OverscaledTileID(0, 0, 0), + "source", + test.tileParameters, + makeMutable(), + loaderActor); tile.setNecessity(TileNecessity::Required); @@ -86,8 +89,11 @@ TEST(CustomGeometryTile, InvokeCancelTile) { auto mb =std::make_shared(*Scheduler::GetCurrent()); ActorRef loaderActor(loader, mb); - CustomGeometryTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, CustomGeometrySource::TileOptions(), - loaderActor); + CustomGeometryTile tile(OverscaledTileID(0, 0, 0), + "source", + test.tileParameters, + makeMutable(), + loaderActor); tile.setNecessity(TileNecessity::Required); tile.setNecessity(TileNecessity::Optional); @@ -108,8 +114,11 @@ TEST(CustomGeometryTile, InvokeTileChanged) { auto mb =std::make_shared(*Scheduler::GetCurrent()); ActorRef loaderActor(loader, mb); - CustomGeometryTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, CustomGeometrySource::TileOptions(), - loaderActor); + CustomGeometryTile tile(OverscaledTileID(0, 0, 0), + "source", + test.tileParameters, + makeMutable(), + loaderActor); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); StubTileObserver observer;