Single-purpose Worker functions

This commit is contained in:
John Firebaugh
2015-06-08 20:08:48 -04:00
parent f14e4c67fd
commit eee02425fa
7 changed files with 126 additions and 102 deletions

View File

@@ -24,44 +24,35 @@ LiveTileData::~LiveTileData() {
cancel();
}
bool LiveTileData::reparse(Worker&, std::function<void()> callback) {
if (parsing.test_and_set(std::memory_order_acquire)) {
bool LiveTileData::reparse(Worker& worker, std::function<void()> callback) {
if (parsing || (state != State::loaded && state != State::partial)) {
return false;
}
workRequest = worker.send([this] {
if (getState() != State::loaded) {
const LiveTile* tile = annotationManager.getTile(id);
if (!tile) {
state = State::parsed;
return true;
}
parsing = true;
workRequest = worker.parseLiveTile(workerData, *tile, [this, callback] (TileParseResult result) {
parsing = false;
if (state == State::obsolete) {
return;
}
const LiveTile* tile = annotationManager.getTile(id);
if (!tile) {
state = State::parsed;
return;
}
TileParseResult result;
try {
result = workerData.parse(*tile);
} catch (const std::exception& ex) {
std::stringstream message;
message << "Failed to parse [" << int(id.sourceZ) << "/" << id.x << "/" << id.y << "]: " << ex.what();
result = message.str();
}
if (getState() == TileData::State::obsolete) {
return;
} else if (result.is<State>()) {
if (result.is<State>()) {
state = result.get<State>();
} else {
error = result.get<std::string>();
state = State::obsolete;
}
parsing.clear(std::memory_order_release);
}, callback);
callback();
});
return true;
}

View File

@@ -42,19 +42,20 @@ void RasterTileData::request(Worker& worker,
}
state = State::loaded;
data = res.data;
workRequest = worker.send([this] {
if (getState() != State::loaded) {
workRequest = worker.parseRasterTile(bucket, res.data, [this, callback] (bool result) {
if (state != State::loaded) {
return;
}
if (bucket.setImage(data)) {
if (result) {
state = State::parsed;
} else {
state = State::invalid;
}
}, callback);
callback();
});
});
}

View File

@@ -30,9 +30,7 @@ public:
private:
const SourceInfo& source;
Request *req = nullptr;
std::string data;
Request* req = nullptr;
StyleLayoutRaster layout;
RasterBucket bucket;

View File

@@ -2,9 +2,7 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/util/pbf.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/storage/file_source.hpp>
@@ -20,15 +18,15 @@ VectorTileData::VectorTileData(const TileID& id_,
float angle,
bool collisionDebug)
: TileData(id_),
source(source_),
worker(style_.workers),
workerData(id_,
style_,
source.max_zoom,
source_.max_zoom,
state,
std::make_unique<CollisionTile>(id_.z, 4096,
source_.tile_size * id.overscaling,
angle, collisionDebug)),
source(source_),
worker(style_.workers),
lastAngle(angle),
currentAngle(angle) {
}
@@ -37,9 +35,7 @@ VectorTileData::~VectorTileData() {
cancel();
}
void VectorTileData::request(Worker&,
float pixelRatio,
const std::function<void()>& callback) {
void VectorTileData::request(Worker&, float pixelRatio, const std::function<void()>& callback) {
std::string url = source.tileURL(id, pixelRatio);
state = State::loading;
@@ -64,37 +60,28 @@ void VectorTileData::request(Worker&,
}
bool VectorTileData::reparse(Worker&, std::function<void()> callback) {
if (parsing.test_and_set(std::memory_order_acquire)) {
if (parsing || (state != State::loaded && state != State::partial)) {
return false;
}
workRequest = worker.send([this] {
if (getState() != TileData::State::loaded && getState() != TileData::State::partial) {
parsing = true;
workRequest = worker.parseVectorTile(workerData, data, [this, callback] (TileParseResult result) {
parsing = false;
if (state == State::obsolete) {
return;
}
TileParseResult result;
try {
VectorTile vectorTile(pbf((const uint8_t *)data.data(), data.size()));
result = workerData.parse(vectorTile);
} catch (const std::exception& ex) {
std::stringstream message;
message << "Failed to parse [" << int(id.sourceZ) << "/" << id.x << "/" << id.y << "]: " << ex.what();
result = message.str();
}
if (getState() == TileData::State::obsolete) {
return;
} else if (result.is<State>()) {
if (result.is<State>()) {
state = result.get<State>();
} else {
error = result.get<std::string>();
state = State::obsolete;
}
parsing.clear(std::memory_order_release);
}, callback);
callback();
});
return true;
}
@@ -111,35 +98,30 @@ size_t VectorTileData::countBuckets() const {
return workerData.countBuckets();
}
void VectorTileData::redoPlacement() {
redoPlacement(lastAngle, lastCollisionDebug);
}
void VectorTileData::redoPlacement(float angle, bool collisionDebug) {
if (angle != currentAngle || collisionDebug != currentCollisionDebug) {
lastAngle = angle;
lastCollisionDebug = collisionDebug;
if (angle == currentAngle && collisionDebug == currentCollisionDebug)
return;
if (getState() != State::parsed || redoingPlacement) return;
lastAngle = angle;
lastCollisionDebug = collisionDebug;
redoingPlacement = true;
currentAngle = angle;
currentCollisionDebug = collisionDebug;
if (state != State::parsed || redoingPlacement)
return;
auto callback = std::bind(&VectorTileData::endRedoPlacement, this);
workRequest = worker.send([this, angle, collisionDebug] { workerData.redoPlacement(angle, collisionDebug); }, callback);
}
}
redoingPlacement = true;
currentAngle = angle;
currentCollisionDebug = collisionDebug;
void VectorTileData::endRedoPlacement() {
for (const auto& layer_desc : workerData.style.layers) {
auto bucket = getBucket(*layer_desc);
if (bucket) {
bucket->swapRenderData();
workRequest = worker.redoPlacement(workerData, angle, collisionDebug, [this] {
for (const auto& layer : workerData.style.layers) {
auto bucket = getBucket(*layer);
if (bucket) {
bucket->swapRenderData();
}
}
}
redoingPlacement = false;
redoPlacement();
redoingPlacement = false;
redoPlacement(lastAngle, lastCollisionDebug);
});
}
void VectorTileData::cancel() {

View File

@@ -39,23 +39,21 @@ public:
void cancel() override;
protected:
void redoPlacement();
const SourceInfo& source;
Request *req = nullptr;
std::string data;
Worker& worker;
TileWorker workerData;
std::unique_ptr<WorkRequest> workRequest;
std::atomic_flag parsing = ATOMIC_FLAG_INIT;
bool parsing = false;
private:
const SourceInfo& source;
Request* req = nullptr;
std::string data;
Worker& worker;
float lastAngle = 0;
float currentAngle;
bool lastCollisionDebug = 0;
bool currentCollisionDebug = 0;
bool redoingPlacement = false;
void endRedoPlacement();
};
}

View File

@@ -2,6 +2,10 @@
#include <mbgl/util/work_task.hpp>
#include <mbgl/util/work_request.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/map/live_tile.hpp>
#include <mbgl/util/pbf.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <cassert>
#include <future>
@@ -16,8 +20,21 @@ public:
util::ThreadContext::setFileSource(fs);
}
void doWork(Fn work) {
work();
bool parseRasterTile(RasterBucket* bucket, std::string data) {
return bucket->setImage(data);
}
TileParseResult parseVectorTile(TileWorker* worker, std::string data) {
VectorTile vectorTile(pbf(reinterpret_cast<const unsigned char *>(data.data()), data.size()));
return worker->parse(vectorTile);
}
TileParseResult parseLiveTile(TileWorker* worker, const LiveTile* tile) {
return worker->parse(*tile);
}
void redoPlacement(TileWorker* worker, float angle, bool collisionDebug) {
worker->redoPlacement(angle, collisionDebug);
}
};
@@ -30,9 +47,24 @@ Worker::Worker(std::size_t count) {
Worker::~Worker() = default;
std::unique_ptr<WorkRequest> Worker::send(Fn work, Fn after) {
std::unique_ptr<WorkRequest> Worker::parseRasterTile(RasterBucket& bucket, std::string data, std::function<void (bool)> callback) {
current = (current + 1) % threads.size();
return threads[current]->invokeWithResult(&Worker::Impl::doWork, after, work);
return threads[current]->invokeWithResult(&Worker::Impl::parseRasterTile, callback, &bucket, data);
}
std::unique_ptr<WorkRequest> Worker::parseVectorTile(TileWorker& worker, std::string data, std::function<void (TileParseResult)> callback) {
current = (current + 1) % threads.size();
return threads[current]->invokeWithResult(&Worker::Impl::parseVectorTile, callback, &worker, data);
}
std::unique_ptr<WorkRequest> Worker::parseLiveTile(TileWorker& worker, const LiveTile& tile, std::function<void (TileParseResult)> callback) {
current = (current + 1) % threads.size();
return threads[current]->invokeWithResult(&Worker::Impl::parseLiveTile, callback, &worker, &tile);
}
std::unique_ptr<WorkRequest> Worker::redoPlacement(TileWorker& worker, float angle, bool collisionDebug, std::function<void ()> callback) {
current = (current + 1) % threads.size();
return threads[current]->invokeWithResult(&Worker::Impl::redoPlacement, callback, &worker, angle, collisionDebug);
}
} // end namespace mbgl

View File

@@ -3,6 +3,7 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/thread.hpp>
#include <mbgl/map/tile_worker.hpp>
#include <functional>
#include <memory>
@@ -10,17 +11,16 @@
namespace mbgl {
class WorkRequest;
class RasterBucket;
class LiveTile;
class Worker : public mbgl::util::noncopyable {
public:
using Fn = std::function<void ()>;
Worker(std::size_t count);
~Worker();
// Request work be done on a thread pool. The optional after callback is
// executed on the invoking thread, which must have a run loop, after the
// work is complete.
// Request work be done on a thread pool. Callbacks are executed on the invoking
// thread, which must have a run loop, after the work is complete.
//
// The return value represents the request to perform the work asynchronously.
// Its destructor guarantees that the work function has finished executing, and
@@ -28,7 +28,29 @@ public:
// Together, this means that an object may make a work request with lambdas which
// bind references to itself, and if and when those lambdas execute, the references
// will still be valid.
std::unique_ptr<WorkRequest> send(Fn work, Fn after);
using Request = std::unique_ptr<WorkRequest>;
Request parseRasterTile(
RasterBucket&,
std::string data,
std::function<void (bool)> callback);
Request parseVectorTile(
TileWorker&,
std::string data,
std::function<void (TileParseResult)> callback);
Request parseLiveTile(
TileWorker&,
const LiveTile&,
std::function<void (TileParseResult)> callback);
Request redoPlacement(
TileWorker&,
float angle,
bool collisionDebug,
std::function<void ()> callback);
private:
class Impl;