Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] Calculate GeoJSON tile geometries in a background thread #15953

Merged
merged 3 commits into from
Nov 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions include/mbgl/style/sources/geojson_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
7 changes: 3 additions & 4 deletions src/mbgl/renderer/sources/render_geojson_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand All @@ -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_);
});
}

Expand Down
62 changes: 30 additions & 32 deletions src/mbgl/style/sources/geojson_source_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -12,51 +13,47 @@
namespace mbgl {
namespace style {

class GeoJSONVTData : public GeoJSONData {
class GeoJSONVTData : public GeoJSONData, public std::enable_shared_from_this<GeoJSONVTData> {
public:
GeoJSONVTData(const GeoJSON& geoJSON, const mapbox::geojsonvt::Options& options)
: 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);
std::weak_ptr<GeoJSONVTData> weak = shared_from_this();
scheduler->scheduleAndReplyValue(
[id, weak, this]() -> TileFeatures {
if (auto self = weak.lock()) {
return impl.getTile(id.z, id.x, id.y).features;
}
return {};
},
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;
}

private:
friend GeoJSONData;
GeoJSONVTData(const GeoJSON& geoJSON, const mapbox::geojsonvt::Options& options)
: impl(geoJSON, options), scheduler(Scheduler::GetSequenced()) {}
mapbox::geojsonvt::GeoJSONVT impl;
std::shared_ptr<Scheduler> scheduler;
};

class SuperclusterData : public GeoJSONData {
public:
SuperclusterData(const mapbox::feature::feature_collection<double>& features,
const mapbox::supercluster::Options& options)
: impl(features, options) {
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<int16_t> getTile(const CanonicalTileID& tileID) final {
return impl.getTile(tileID.z, tileID.x, tileID.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);
}

Expand All @@ -65,6 +62,9 @@ class SuperclusterData : public GeoJSONData {
}

private:
friend GeoJSONData;
SuperclusterData(const Features& features, const mapbox::supercluster::Options& options)
: impl(features, options) {}
mapbox::supercluster::Supercluster impl;
};

Expand All @@ -85,8 +85,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;
Expand All @@ -111,8 +110,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::shared_ptr<GeoJSONData>(new SuperclusterData(geoJSON.get<Features>(), clusterOptions));
}

mapbox::geojsonvt::Options vtOptions;
Expand All @@ -121,7 +119,7 @@ std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON, Immutab
vtOptions.buffer = ::round(scale * options->buffer);
vtOptions.tolerance = scale * options->tolerance;
vtOptions.lineMetrics = options->lineMetrics;
return std::make_shared<GeoJSONVTData>(geoJSON, vtOptions);
return std::shared_ptr<GeoJSONData>(new GeoJSONVTData(geoJSON, vtOptions));
}

GeoJSONSource::Impl::Impl(std::string id_, Immutable<GeoJSONOptions> options_)
Expand Down
24 changes: 17 additions & 7 deletions src/mbgl/tile/geojson_tile.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
#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_), false /*needsRelayout*/);
}

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 needsRelayout) {
assert(data_);
data = std::move(data_);
if (needsRelayout) reset();
data->getTile(
id.canonical,
[this, self = weakFactory.makeWeakPtr(), capturedData = data.get()](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));
});
}

void GeoJSONTile::querySourceFeatures(
Expand Down
11 changes: 9 additions & 2 deletions src/mbgl/tile/geojson_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <mbgl/util/feature.hpp>

namespace mbgl {
namespace style {
class GeoJSONData;
} // namespace style

class TileParameters;

Expand All @@ -12,13 +15,17 @@ class GeoJSONTile : public GeometryTile {
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 needsRelayout = 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
13 changes: 11 additions & 2 deletions src/mbgl/tile/geometry_tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,23 @@ void GeometryTile::setError(std::exception_ptr err) {
observer->onTileError(*this, err);
}

void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_, bool resetLayers) {
void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) {
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
pending = true;

++correlationID;
worker.self().invoke(
&GeometryTileWorker::setData, std::move(data_), imageManager.getAvailableImages(), resetLayers, correlationID);
&GeometryTileWorker::setData, std::move(data_), imageManager.getAvailableImages(), correlationID);
}

void GeometryTile::reset() {
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
pending = true;

++correlationID;
worker.self().invoke(&GeometryTileWorker::reset, correlationID);
}

std::unique_ptr<TileRenderData> GeometryTile::createRenderData() {
Expand Down
5 changes: 4 additions & 1 deletion src/mbgl/tile/geometry_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ class GeometryTile : public Tile, public GlyphRequestor, public ImageRequestor {
~GeometryTile() override;

void setError(std::exception_ptr);
void setData(std::unique_ptr<const GeometryTileData>, bool resetLayers = false);
void setData(std::unique_ptr<const GeometryTileData>);
// Resets the tile's data and layers and leaves the tile in pending state, waiting for the new
// data and layers to come.
void reset();

std::unique_ptr<TileRenderData> createRenderData() override;
void setLayers(const std::vector<Immutable<style::LayerProperties>>&) override;
Expand Down
18 changes: 16 additions & 2 deletions src/mbgl/tile/geometry_tile_worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,11 @@ GeometryTileWorker::~GeometryTileWorker() = default;

void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_,
std::set<std::string> availableImages_,
bool resetLayers_,
uint64_t correlationID_) {
try {
data = std::move(data_);
correlationID = correlationID_;
availableImages = std::move(availableImages_);
if (resetLayers_) layers = nullopt;

switch (state) {
case Idle:
Expand Down Expand Up @@ -170,6 +168,22 @@ void GeometryTileWorker::setLayers(std::vector<Immutable<LayerProperties>> layer
}
}

void GeometryTileWorker::reset(uint64_t correlationID_) {
layers = nullopt;
data = nullopt;
correlationID = correlationID_;

switch (state) {
case Idle:
case NeedsParse:
break;
case Coalescing:
case NeedsSymbolLayout:
state = NeedsParse;
break;
}
}

void GeometryTileWorker::setShowCollisionBoxes(bool showCollisionBoxes_, uint64_t correlationID_) {
try {
showCollisionBoxes = showCollisionBoxes_;
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/tile/geometry_tile_worker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class GeometryTileWorker {
uint64_t correlationID);
void setData(std::unique_ptr<const GeometryTileData>,
std::set<std::string> availableImages,
bool resetLayers,
uint64_t correlationID);
void reset(uint64_t correlationID_);
void setShowCollisionBoxes(bool showCollisionBoxes_, uint64_t correlationID_);

void onGlyphsAvailable(GlyphMap glyphs);
Expand Down
Loading