[core] Merge LiveTileData into VectorTileData
To encapsulate the differences, this introduces an abstract GeometryTileMonitor class, with concrete VectorTileMonitor and AnnotationTileMonitor implementations, and makes pbf parsing for VectorTile data happen lazily in getLayer, since we want that to happen on the worker thread, rather than when VectorTile is created. Fixes #2792
This commit is contained in:
@@ -1,112 +1,97 @@
|
||||
#include <mbgl/map/vector_tile_data.hpp>
|
||||
#include <mbgl/map/geometry_tile.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
#include <mbgl/style/style_bucket.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/text/collision_tile.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>
|
||||
#include <mbgl/style/style.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
#include <sstream>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
VectorTileData::VectorTileData(const TileID& id_,
|
||||
std::unique_ptr<GeometryTileMonitor> monitor_,
|
||||
std::string sourceID,
|
||||
Style& style_,
|
||||
const SourceInfo& source_)
|
||||
const std::function<void()>& callback)
|
||||
: TileData(id_),
|
||||
worker(style_.workers),
|
||||
tileWorker(id_,
|
||||
source_.source_id,
|
||||
sourceID,
|
||||
style_,
|
||||
style_.layers,
|
||||
state),
|
||||
source(source_) {
|
||||
}
|
||||
|
||||
VectorTileData::~VectorTileData() {
|
||||
cancel();
|
||||
}
|
||||
|
||||
void VectorTileData::request(float pixelRatio, const std::function<void()>& callback) {
|
||||
std::string url = source.tileURL(id, pixelRatio);
|
||||
monitor(std::move(monitor_))
|
||||
{
|
||||
state = State::loading;
|
||||
|
||||
FileSource* fs = util::ThreadContext::getFileSource();
|
||||
req = fs->request({ Resource::Kind::Tile, url }, util::RunLoop::getLoop(), [url, callback, this](const Response &res) {
|
||||
// Do not cancel the request here; we want to get notified about tiles that expire.
|
||||
|
||||
if (res.data && data == res.data) {
|
||||
// We got the same data again. Abort early.
|
||||
return;
|
||||
req = monitor->monitorTile([callback, sourceID, this](std::exception_ptr err, std::unique_ptr<GeometryTile> tile) {
|
||||
if (err) {
|
||||
try {
|
||||
std::rethrow_exception(err);
|
||||
} catch (const std::exception& e) {
|
||||
error = e.what();
|
||||
state = State::obsolete;
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (res.status == Response::NotFound) {
|
||||
if (!tile) {
|
||||
state = State::parsed;
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.status != Response::Successful) {
|
||||
std::stringstream message;
|
||||
message << "Failed to load [" << url << "]: " << res.message;
|
||||
error = message.str();
|
||||
state = State::obsolete;
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == State::loading) {
|
||||
state = State::loaded;
|
||||
} else if (isReady()) {
|
||||
state = State::partial;
|
||||
}
|
||||
data = res.data;
|
||||
|
||||
parse(callback);
|
||||
// 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, std::move(tile), targetConfig, [callback, sourceID, this, config = targetConfig] (TileParseResult result) {
|
||||
workRequest.reset();
|
||||
if (state == State::obsolete) {
|
||||
return;
|
||||
}
|
||||
|
||||
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.
|
||||
for (auto& bucket : resultBuckets.buckets) {
|
||||
buckets[bucket.first] = std::move(bucket.second);
|
||||
}
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
} else {
|
||||
std::stringstream message;
|
||||
message << "Failed to parse [" << std::string(id) << "]: " << result.get<std::string>();
|
||||
error = message.str();
|
||||
state = State::obsolete;
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void VectorTileData::parse(std::function<void ()> callback) {
|
||||
// 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.parseVectorTile(tileWorker, data, targetConfig, [this, callback, config = targetConfig] (TileParseResult result) {
|
||||
workRequest.reset();
|
||||
if (state == State::obsolete) {
|
||||
return;
|
||||
}
|
||||
|
||||
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.
|
||||
for (auto& bucket : resultBuckets.buckets) {
|
||||
buckets[bucket.first] = std::move(bucket.second);
|
||||
}
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
} else {
|
||||
std::stringstream message;
|
||||
message << "Failed to parse [" << std::string(id) << "]: " << result.get<std::string>();
|
||||
error = message.str();
|
||||
state = State::obsolete;
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
VectorTileData::~VectorTileData() {
|
||||
cancel();
|
||||
}
|
||||
|
||||
bool VectorTileData::parsePending(std::function<void()> callback) {
|
||||
@@ -116,7 +101,7 @@ bool VectorTileData::parsePending(std::function<void()> callback) {
|
||||
}
|
||||
|
||||
workRequest.reset();
|
||||
workRequest = worker.parsePendingVectorTileLayers(tileWorker, [this, callback] (TileParseResult result) {
|
||||
workRequest = worker.parsePendingGeometryTileLayers(tileWorker, [this, callback] (TileParseResult result) {
|
||||
workRequest.reset();
|
||||
if (state == State::obsolete) {
|
||||
return;
|
||||
@@ -204,3 +189,5 @@ void VectorTileData::cancel() {
|
||||
req = nullptr;
|
||||
workRequest.reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user