diff options
author | Mikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com> | 2019-11-20 21:05:45 +0200 |
---|---|---|
committer | Mikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com> | 2019-11-29 11:12:55 +0200 |
commit | 6419cd0ab2ba877bbae51ae7590ddba47765dac7 (patch) | |
tree | b167f864db677365d281423e1df755f7fd383989 | |
parent | ab5572b0bc3d386893592b842ad58b356b227a5d (diff) | |
download | qtlocation-mapboxgl-6419cd0ab2ba877bbae51ae7590ddba47765dac7.tar.gz |
[core] Calculate GeoJSON tile geometries in a background thread
Call `mapbox::geojsonvt::GeoJSONVT::getTile()` in a background
thread, so that the rendering thread is not blocked.
-rw-r--r-- | include/mbgl/style/sources/geojson_source.hpp | 12 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_geojson_source.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/style/sources/geojson_source_impl.cpp | 43 | ||||
-rw-r--r-- | src/mbgl/tile/geojson_tile.cpp | 23 | ||||
-rw-r--r-- | src/mbgl/tile/geojson_tile.hpp | 11 | ||||
-rw-r--r-- | test/tile/geojson_tile.test.cpp | 42 |
6 files changed, 86 insertions, 52 deletions
diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index 1cc104b245..9569b61df4 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -39,17 +39,19 @@ struct GeoJSONOptions { }; class GeoJSONData { public: + using TileFeatures = mapbox::feature::feature_collection<int16_t>; + using Features = mapbox::feature::feature_collection<double>; static std::shared_ptr<GeoJSONData> create(const GeoJSON&, Immutable<GeoJSONOptions> = GeoJSONOptions::defaultOptions()); virtual ~GeoJSONData() = default; - virtual mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID&) = 0; + virtual void getTile(const CanonicalTileID&, const std::function<void(TileFeatures)>&) = 0; // SuperclusterData - virtual mapbox::feature::feature_collection<double> getChildren(const std::uint32_t) = 0; - virtual mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t, - const std::uint32_t limit = 10u, - const std::uint32_t offset = 0u) = 0; + virtual Features getChildren(const std::uint32_t) = 0; + virtual Features getLeaves(const std::uint32_t, + const std::uint32_t limit = 10u, + const std::uint32_t offset = 0u) = 0; virtual std::uint8_t getClusterExpansionZoom(std::uint32_t) = 0; }; diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 4ed9dd9334..94d171cf18 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -95,8 +95,7 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_, const uint8_t maxZ = impl().getZoomRange().max; for (const auto& pair : tilePyramid.getTiles()) { if (pair.first.canonical.z <= maxZ) { - static_cast<GeoJSONTile*>(pair.second.get()) - ->updateData(data_->getTile(pair.first.canonical), needsRelayout); + static_cast<GeoJSONTile*>(pair.second.get())->updateData(data_, needsRelayout); } } } @@ -112,8 +111,8 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_, util::tileSize, impl().getZoomRange(), optional<LatLngBounds>{}, - [&, data_] (const OverscaledTileID& tileID) { - return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data_->getTile(tileID.canonical)); + [&, data_](const OverscaledTileID& tileID) { + return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data_); }); } diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index 962d6bd060..e4b48223f4 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -3,6 +3,7 @@ #include <mbgl/util/constants.hpp> #include <mbgl/util/feature.hpp> #include <mbgl/util/string.hpp> +#include <mbgl/util/thread_pool.hpp> #include <mapbox/geojsonvt.hpp> #include <supercluster.hpp> @@ -18,18 +19,16 @@ public: : impl(geoJSON, options) { } - mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final { - return impl.getTile(tileID.z, tileID.x, tileID.y).features; + void getTile(const CanonicalTileID& id, const std::function<void(TileFeatures)>& fn) final { + assert(fn); + // It's safe to pass `this` as scheduler will die earlier. + scheduler.scheduleAndReplyValue( + [id, this]() -> TileFeatures { return impl.getTile(id.z, id.x, id.y).features; }, fn); } - mapbox::feature::feature_collection<double> getChildren(const std::uint32_t) final { - return {}; - } + Features getChildren(const std::uint32_t) final { return {}; } - mapbox::feature::feature_collection<double> - getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final { - return {}; - } + Features getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final { return {}; } std::uint8_t getClusterExpansionZoom(std::uint32_t) final { return 0; @@ -37,26 +36,22 @@ public: private: mapbox::geojsonvt::GeoJSONVT impl; + SequencedScheduler scheduler; }; class SuperclusterData : public GeoJSONData { public: - SuperclusterData(const mapbox::feature::feature_collection<double>& features, - const mapbox::supercluster::Options& options) - : impl(features, options) { - } + SuperclusterData(const Features& features, const mapbox::supercluster::Options& options) + : impl(features, options) {} - mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final { - return impl.getTile(tileID.z, tileID.x, tileID.y); + void getTile(const CanonicalTileID& id, const std::function<void(TileFeatures)>& fn) final { + assert(fn); + fn(impl.getTile(id.z, id.x, id.y)); } - mapbox::feature::feature_collection<double> getChildren(const std::uint32_t cluster_id) final { - return impl.getChildren(cluster_id); - } + Features getChildren(const std::uint32_t cluster_id) final { return impl.getChildren(cluster_id); } - mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t cluster_id, - const std::uint32_t limit, - const std::uint32_t offset) final { + Features getLeaves(const std::uint32_t cluster_id, const std::uint32_t limit, const std::uint32_t offset) final { return impl.getLeaves(cluster_id, limit, offset); } @@ -85,8 +80,7 @@ T evaluateFeature(const mapbox::feature::feature<double>& f, // static std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON, Immutable<GeoJSONOptions> options) { constexpr double scale = util::EXTENT / util::tileSize; - if (options->cluster && geoJSON.is<mapbox::feature::feature_collection<double>>() && - !geoJSON.get<mapbox::feature::feature_collection<double>>().empty()) { + if (options->cluster && geoJSON.is<Features>() && !geoJSON.get<Features>().empty()) { mapbox::supercluster::Options clusterOptions; clusterOptions.maxZoom = options->clusterMaxZoom; clusterOptions.extent = util::EXTENT; @@ -111,8 +105,7 @@ std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON, Immutab toReturn[p.first] = evaluateFeature<Value>(*feature, p.second.second, accumulated); } }; - return std::make_shared<SuperclusterData>(geoJSON.get<mapbox::feature::feature_collection<double>>(), - clusterOptions); + return std::make_shared<SuperclusterData>(geoJSON.get<Features>(), clusterOptions); } mapbox::geojsonvt::Options vtOptions; diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 0782f74d5d..a4c48fb809 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -1,20 +1,29 @@ -#include <mbgl/tile/geojson_tile.hpp> -#include <mbgl/tile/geojson_tile_data.hpp> #include <mbgl/renderer/query.hpp> #include <mbgl/renderer/tile_parameters.hpp> - +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/tile/geojson_tile.hpp> +#include <mbgl/tile/geojson_tile_data.hpp> namespace mbgl { GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID, std::string sourceID_, const TileParameters& parameters, - mapbox::feature::feature_collection<int16_t> features) + std::shared_ptr<style::GeoJSONData> data_) : GeometryTile(overscaledTileID, sourceID_, parameters) { - updateData(std::move(features)); + updateData(std::move(data_)); } -void GeoJSONTile::updateData(mapbox::feature::feature_collection<int16_t> features, bool resetLayers) { - setData(std::make_unique<GeoJSONTileData>(std::move(features)), resetLayers); +void GeoJSONTile::updateData(std::shared_ptr<style::GeoJSONData> data_, bool resetLayers) { + assert(data_); + data = std::move(data_); + data->getTile(id.canonical, + [this, self = weakFactory.makeWeakPtr(), capturedData = data.get(), resetLayers]( + style::GeoJSONData::TileFeatures features) { + if (!self) return; + if (data.get() != capturedData) return; + auto tileData = std::make_unique<GeoJSONTileData>(std::move(features)); + setData(std::move(tileData), resetLayers); + }); } void GeoJSONTile::querySourceFeatures( diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp index 9161e33f0c..26dc300bdc 100644 --- a/src/mbgl/tile/geojson_tile.hpp +++ b/src/mbgl/tile/geojson_tile.hpp @@ -4,6 +4,9 @@ #include <mbgl/util/feature.hpp> namespace mbgl { +namespace style { +class GeoJSONData; +} // namespace style class TileParameters; @@ -12,13 +15,17 @@ public: GeoJSONTile(const OverscaledTileID&, std::string sourceID, const TileParameters&, - mapbox::feature::feature_collection<int16_t>); + std::shared_ptr<style::GeoJSONData>); - void updateData(mapbox::feature::feature_collection<int16_t>, bool resetLayers = false); + void updateData(std::shared_ptr<style::GeoJSONData> data, bool resetLayers = false); void querySourceFeatures( std::vector<Feature>& result, const SourceQueryOptions&) override; + +private: + std::shared_ptr<style::GeoJSONData> data; + mapbox::base::WeakPtrFactory<GeoJSONTile> weakFactory{this}; }; } // namespace mbgl diff --git a/test/tile/geojson_tile.test.cpp b/test/tile/geojson_tile.test.cpp index cc2dbfced8..d4bf1e0752 100644 --- a/test/tile/geojson_tile.test.cpp +++ b/test/tile/geojson_tile.test.cpp @@ -4,15 +4,16 @@ #include <mbgl/tile/geojson_tile.hpp> #include <mbgl/tile/tile_loader_impl.hpp> -#include <mbgl/util/run_loop.hpp> +#include <mbgl/annotation/annotation_manager.hpp> #include <mbgl/map/transform.hpp> +#include <mbgl/renderer/image_manager.hpp> #include <mbgl/renderer/tile_parameters.hpp> -#include <mbgl/style/style.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/circle_layer_impl.hpp> -#include <mbgl/annotation/annotation_manager.hpp> -#include <mbgl/renderer/image_manager.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/style.hpp> #include <mbgl/text/glyph_manager.hpp> +#include <mbgl/util/run_loop.hpp> #include <memory> @@ -43,6 +44,29 @@ public: }; }; +namespace { + +class FakeGeoJSONData : public GeoJSONData { +public: + FakeGeoJSONData(TileFeatures features_) : features(std::move(features_)) {} + + void getTile(const CanonicalTileID&, const std::function<void(TileFeatures)>& fn) final { + assert(fn); + fn(features); + } + + Features getChildren(const std::uint32_t) final { return {}; } + + Features getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final { return {}; } + + std::uint8_t getClusterExpansionZoom(std::uint32_t) final { return 0; } + +private: + TileFeatures features; +}; + +} // namespace + TEST(GeoJSONTile, Issue7648) { GeoJSONTileTest test; @@ -50,8 +74,8 @@ TEST(GeoJSONTile, Issue7648) { mapbox::feature::feature_collection<int16_t> features; features.push_back(mapbox::feature::feature<int16_t> { mapbox::geometry::point<int16_t>(0, 0) }); - - GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, features); + auto data = std::make_shared<FakeGeoJSONData>(std::move(features)); + GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, data); Immutable<LayerProperties> layerProperties = makeMutable<CircleLayerProperties>(staticImmutableCast<CircleLayer::Impl>(layer.baseImpl)); StubTileObserver observer; observer.tileChanged = [&] (const Tile&) { @@ -68,7 +92,7 @@ TEST(GeoJSONTile, Issue7648) { test.loop.runOnce(); } - tile.updateData(features); + tile.updateData(data); while (!tile.isComplete()) { test.loop.runOnce(); } @@ -83,8 +107,8 @@ TEST(GeoJSONTile, Issue9927) { mapbox::feature::feature_collection<int16_t> features; features.push_back(mapbox::feature::feature<int16_t> { mapbox::geometry::point<int16_t>(0, 0) }); - - GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, features); + auto data = std::make_shared<FakeGeoJSONData>(std::move(features)); + GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, data); Immutable<LayerProperties> layerProperties = makeMutable<CircleLayerProperties>(staticImmutableCast<CircleLayer::Impl>(layer.baseImpl)); std::vector<Immutable<LayerProperties>> layers { layerProperties }; |