Merge branch 'master' into libuv-0.10-headless-display

Conflicts:
	common/curl_request.cpp
	common/glfw_view.cpp
	common/glfw_view.hpp
	include/mbgl/platform/request.hpp
	ios/mapbox-gl-cocoa
	setup-libraries.sh
	src/map/map.cpp
	src/platform/request.cpp
	test/fixtures/fixture_request.cpp
This commit is contained in:
Mike Morris
2014-10-10 12:24:45 -04:00
115 changed files with 5035 additions and 866 deletions

View File

@@ -19,11 +19,10 @@
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/util/texturepool.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/util/filesource.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/platform/log.hpp>
#include <algorithm>
#include <memory>
#include <iostream>
#define _USE_MATH_DEFINES
@@ -34,12 +33,15 @@ using namespace mbgl;
Map::Map(View& view)
: loop(std::make_shared<uv::loop>()),
thread(std::make_unique<uv::thread>()),
async_terminate(new uv_async_t()),
async_render(new uv_async_t()),
async_cleanup(new uv_async_t()),
view(view),
#ifndef NDEBUG
main_thread(uv_thread_self()),
#endif
transform(view),
fileSource(std::make_shared<FileSource>()),
style(std::make_shared<Style>()),
glyphAtlas(std::make_shared<GlyphAtlas>(1024, 1024)),
glyphStore(std::make_shared<GlyphStore>(fileSource)),
spriteAtlas(std::make_shared<SpriteAtlas>(512, 512)),
texturepool(std::make_shared<Texturepool>()),
painter(*this) {
@@ -53,49 +55,93 @@ Map::Map(View& view)
}
Map::~Map() {
// Clear the style first before the rest of the constructor deletes members of this object.
// This is required because members of the style reference the Map object in their destructors.
style.reset();
if (async) {
stop();
}
// Explicitly reset all pointers.
texturepool.reset();
sprite.reset();
spriteAtlas.reset();
glyphStore.reset();
glyphAtlas.reset();
style.reset();
fileSource.reset();
workers.reset();
uv_run(**loop, UV_RUN_DEFAULT);
}
uv::worker &Map::getWorker() {
if (!workers) {
workers = std::make_unique<uv::worker>(**loop, 4, "Tile Worker");
}
return *workers;
}
void Map::start() {
assert(uv_thread_self() == main_thread);
assert(!async);
// When starting map rendering in another thread, we perform async/continuously
// updated rendering. Only in these cases, we attach the async handlers.
async = true;
// Setup async notifications
async_terminate = new uv_async_t();
uv_async_init(**loop, async_terminate, terminate);
async_terminate->data = **loop;
// Reset the flag.
is_stopped = false;
async_render = new uv_async_t();
uv_async_init(**loop, async_render, render);
// Setup async notifications
uv_async_init(**loop, async_terminate.get(), terminate);
async_terminate->data = this;
uv_async_init(**loop, async_render.get(), render);
async_render->data = this;
async_cleanup = new uv_async_t();
uv_async_init(**loop, async_cleanup, cleanup);
uv_async_init(**loop, async_cleanup.get(), cleanup);
async_cleanup->data = this;
uv_thread_create(*thread, [](void *arg) {
Map *map = static_cast<Map *>(arg);
#ifndef NDEBUG
map->map_thread = uv_thread_self();
#endif
#ifdef __APPLE__
pthread_setname_np("Map");
#endif
map->run();
#ifndef NDEBUG
map->map_thread = -1;
#endif
// Make sure that the stop() function knows when to stop invoking the callback function.
map->is_stopped = true;
map->view.notify();
}, this);
}
void Map::stop() {
if (async_terminate != nullptr) {
uv_async_send(async_terminate);
void Map::stop(stop_callback cb, void *data) {
assert(uv_thread_self() == main_thread);
assert(main_thread != map_thread);
assert(async);
uv_async_send(async_terminate.get());
if (cb) {
// Wait until the render thread stopped. We are using this construct instead of plainly
// relying on the thread_join because the system might need to run things in the current
// thread that is required for the render thread to terminate correctly. This is for example
// the case with Cocoa's NSURLRequest. Otherwise, we will eventually deadlock because this
// thread (== main thread) is blocked. The callback function should use an efficient waiting
// function to avoid a busy waiting loop.
while (!is_stopped) {
cb(data);
}
}
// If a callback function was provided, this should return immediately because the thread has
// already finished executing.
uv_thread_join(*thread);
// Run the event loop once to make sure our async delete handlers are called.
uv_run(**loop, UV_RUN_ONCE);
async = false;
}
@@ -104,22 +150,35 @@ void Map::delete_async(uv_handle_t *handle, int status) {
}
void Map::run() {
#ifndef NDEBUG
if (!async) {
map_thread = main_thread;
}
#endif
assert(uv_thread_self() == map_thread);
setup();
prepare();
uv_run(**loop, UV_RUN_DEFAULT);
// Run the event loop once more to make sure our async delete handlers are called.
uv_run(**loop, UV_RUN_ONCE);
// If the map rendering wasn't started asynchronously, we perform one render
// *after* all events have been processed.
if (!async) {
render();
#ifndef NDEBUG
map_thread = -1;
#endif
}
}
void Map::rerender() {
// We only send render events if we want to continuously update the map
// (== async rendering).
if (async && async_render != nullptr) {
uv_async_send(async_render);
if (async) {
uv_async_send(async_render.get());
}
}
@@ -139,7 +198,7 @@ void Map::swapped() {
void Map::cleanup() {
if (async_cleanup != nullptr) {
uv_async_send(async_cleanup);
uv_async_send(async_cleanup.get());
}
}
@@ -153,9 +212,20 @@ void Map::terminate() {
painter.terminate();
}
void Map::setReachability(bool reachable) {
// Note: This function may be called from *any* thread.
if (reachable) {
if (fileSource) {
fileSource->prepare([&]() {
fileSource->retryAllPending();
});
}
}
}
void Map::render(uv_async_t *async, int status) {
Map *map = static_cast<Map *>(async->data);
assert(uv_thread_self() == map->map_thread);
if (map->state.hasSize()) {
if (map->is_rendered.test_and_set() == false) {
@@ -175,44 +245,48 @@ void Map::render(uv_async_t *async, int status) {
void Map::terminate(uv_async_t *async, int status) {
// Closes all open handles on the loop. This means that the loop will automatically terminate.
uv_loop_t *loop = static_cast<uv_loop_t *>(async->data);
uv_walk(loop, [](uv_handle_t *handle, void */*arg*/) {
if (!uv_is_closing(handle)) {
uv_close(handle, NULL);
}
}, NULL);
Map *map = static_cast<Map *>(async->data);
assert(uv_thread_self() == map->map_thread);
// Remove all of these to make sure they are destructed in the correct thread.
map->glyphStore.reset();
map->fileSource.reset();
map->style.reset();
map->workers.reset();
map->activeSources.clear();
uv_close((uv_handle_t *)map->async_cleanup.get(), nullptr);
uv_close((uv_handle_t *)map->async_render.get(), nullptr);
uv_close((uv_handle_t *)map->async_terminate.get(), nullptr);
}
#pragma mark - Setup
void Map::setup() {
assert(uv_thread_self() == map_thread);
view.make_active();
painter.setup();
view.make_inactive();
}
void Map::setStyleURL(const std::string &url) {
fileSource->load(ResourceType::JSON, url, [&](platform::Response *res) {
if (res->code == 200) {
// Calculate the base
const size_t pos = url.rfind('/');
std::string base = "";
if (pos != std::string::npos) {
base = url.substr(0, pos + 1);
}
this->setStyleJSON(res->body, base);
} else {
Log::Error(Event::Setup, "loading style failed: %d (%s)", res->code, res->error_message.c_str());
}
}, loop);
// TODO: Make threadsafe.
styleURL = url;
}
void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) {
// TODO: Make threadsafe.
styleJSON.swap(newStyleJSON);
sprite.reset();
if (!style) {
style = std::make_shared<Style>();
}
style->loadJSON((const uint8_t *)styleJSON.c_str());
if (!fileSource) {
fileSource = std::make_shared<FileSource>(**loop, platform::defaultCacheDatabase());
glyphStore = std::make_shared<GlyphStore>(fileSource);
}
fileSource->setBase(base);
glyphStore->setURL(util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken()));
update();
@@ -223,6 +297,7 @@ std::string Map::getStyleJSON() const {
}
void Map::setAccessToken(std::string access_token) {
// TODO: Make threadsafe.
accessToken.swap(access_token);
}
@@ -230,7 +305,7 @@ std::string Map::getAccessToken() const {
return accessToken;
}
std::shared_ptr<Sprite> Map::getSprite() {
util::ptr<Sprite> Map::getSprite() {
const float pixelRatio = state.getPixelRatio();
const std::string &sprite_url = style->getSpriteURL();
if (!sprite || sprite->pixelRatio != pixelRatio) {
@@ -460,8 +535,10 @@ void Map::setDefaultTransitionDuration(uint64_t duration_milliseconds) {
}
void Map::updateSources() {
assert(uv_thread_self() == map_thread);
// First, disable all existing sources.
for (const std::shared_ptr<StyleSource> &source : activeSources) {
for (const util::ptr<StyleSource> &source : activeSources) {
source->enabled = false;
}
@@ -469,7 +546,7 @@ void Map::updateSources() {
updateSources(style->layers);
// Then, construct or destroy the actual source object, depending on enabled state.
for (const std::shared_ptr<StyleSource> &style_source : activeSources) {
for (const util::ptr<StyleSource> &style_source : activeSources) {
if (style_source->enabled) {
if (!style_source->source) {
style_source->source = std::make_shared<Source>(style_source->info);
@@ -481,20 +558,20 @@ void Map::updateSources() {
}
// Finally, remove all sources that are disabled.
util::erase_if(activeSources, [](std::shared_ptr<StyleSource> source){
util::erase_if(activeSources, [](util::ptr<StyleSource> source){
return !source->enabled;
});
}
const std::set<std::shared_ptr<StyleSource>> Map::getActiveSources() const {
const std::set<util::ptr<StyleSource>> Map::getActiveSources() const {
return activeSources;
}
void Map::updateSources(const std::shared_ptr<StyleLayerGroup> &group) {
void Map::updateSources(const util::ptr<StyleLayerGroup> &group) {
if (!group) {
return;
}
for (const std::shared_ptr<StyleLayer> &layer : group->layers) {
for (const util::ptr<StyleLayer> &layer : group->layers) {
if (!layer) continue;
if (layer->bucket) {
if (layer->bucket->style_source) {
@@ -507,7 +584,7 @@ void Map::updateSources(const std::shared_ptr<StyleLayerGroup> &group) {
}
void Map::updateTiles() {
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
for (const util::ptr<StyleSource> &source : getActiveSources()) {
source->source->update(*this);
}
}
@@ -515,13 +592,37 @@ void Map::updateTiles() {
void Map::updateRenderState() {
// Update all clipping IDs.
ClipIDGenerator generator;
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
for (const util::ptr<StyleSource> &source : getActiveSources()) {
generator.update(source->source->getLoadedTiles());
source->source->updateMatrices(painter.projMatrix, state);
}
}
void Map::prepare() {
if (!fileSource) {
fileSource = std::make_shared<FileSource>(**loop, platform::defaultCacheDatabase());
glyphStore = std::make_shared<GlyphStore>(fileSource);
}
if (!style) {
style = std::make_shared<Style>();
fileSource->request(ResourceType::JSON, styleURL)->onload([&](const Response &res) {
if (res.code == 200) {
// Calculate the base
const size_t pos = styleURL.rfind('/');
std::string base = "";
if (pos != std::string::npos) {
base = styleURL.substr(0, pos + 1);
}
setStyleJSON(res.data, base);
} else {
Log::Error(Event::Setup, "loading style failed: %ld (%s)", res.code, res.message.c_str());
}
});
}
// Update transform transitions.
animationTime = util::now();
if (transform.needsTransition()) {
@@ -568,7 +669,7 @@ void Map::render() {
// This guarantees that we have at least one function per tile called.
// When only rendering layers via the stylesheet, it's possible that we don't
// ever visit a tile during rendering.
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
for (const util::ptr<StyleSource> &source : getActiveSources()) {
source->source->finishRender(painter);
}
@@ -582,7 +683,7 @@ void Map::render() {
view.make_inactive();
}
void Map::renderLayers(std::shared_ptr<StyleLayerGroup> group) {
void Map::renderLayers(util::ptr<StyleLayerGroup> group) {
if (!group) {
// Make sure that we actually do have a layer group.
return;
@@ -625,7 +726,7 @@ void Map::renderLayers(std::shared_ptr<StyleLayerGroup> group) {
}
}
void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass, const Tile::ID* id, const mat4* matrix) {
void Map::renderLayer(util::ptr<StyleLayer> layer_desc, RenderPass pass, const Tile::ID* id, const mat4* matrix) {
if (layer_desc->type == StyleLayerType::Background) {
// This layer defines a background color/image.

View File

@@ -5,7 +5,7 @@
using namespace mbgl;
RasterTileData::RasterTileData(Tile::ID id, Map &map, const SourceInfo &source)
RasterTileData::RasterTileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source)
: TileData(id, map, source),
bucket(map.getTexturepool(), properties) {
}
@@ -25,10 +25,10 @@ void RasterTileData::parse() {
}
}
void RasterTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix) {
void RasterTileData::render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) {
bucket.render(painter, layer_desc, id, matrix);
}
bool RasterTileData::hasData(std::shared_ptr<StyleLayer> /*layer_desc*/) const {
bool RasterTileData::hasData(util::ptr<StyleLayer> /*layer_desc*/) const {
return bucket.hasData();
}

View File

@@ -6,7 +6,7 @@
#include <mbgl/util/raster.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/texturepool.hpp>
#include <mbgl/util/filesource.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/util/vec.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/std.hpp>
@@ -20,7 +20,7 @@
namespace mbgl {
Source::Source(SourceInfo& info)
Source::Source(const util::ptr<SourceInfo>& info)
: info(info)
{
}
@@ -29,32 +29,33 @@ Source::Source(SourceInfo& info)
// The reason this isn't part of the constructor is that calling shared_from_this() in
// the constructor fails.
void Source::load(Map& map) {
if (info.url.empty()) {
if (info->url.empty()) {
loaded = true;
return;
}
std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken());
std::shared_ptr<Source> source = shared_from_this();
std::string url = util::mapbox::normalizeSourceURL(info->url, map.getAccessToken());
util::ptr<Source> source = shared_from_this();
map.getFileSource()->load(ResourceType::JSON, url, [source, &map](platform::Response *res) {
if (res->code != 200) {
map.getFileSource()->request(ResourceType::JSON, url)->onload([source, &map](const Response &res) {
if (res.code != 200) {
Log::Warning(Event::General, "failed to load source TileJSON");
return;
}
rapidjson::Document d;
d.Parse<0>(res->body.c_str());
d.Parse<0>(res.data.c_str());
if (d.HasParseError()) {
Log::Warning(Event::General, "invalid source TileJSON");
return;
}
source->info.parseTileJSONProperties(d);
source->info->parseTileJSONProperties(d);
source->loaded = true;
map.update();
});
}
@@ -98,7 +99,7 @@ void Source::drawClippingMasks(Painter &painter) {
}
}
void Source::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) {
void Source::render(Painter &painter, util::ptr<StyleLayer> layer_desc) {
gl::group group(std::string("layer: ") + layer_desc->id);
for (const std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
@@ -108,7 +109,7 @@ void Source::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) {
}
}
void Source::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
void Source::render(Painter &painter, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
auto it = tiles.find(id);
if (it != tiles.end() && it->second->data && it->second->data->state == TileData::State::parsed) {
painter.renderTileLayer(*it->second, layer_desc, matrix);
@@ -183,9 +184,9 @@ TileData::State Source::addTile(Map &map, const Tile::ID& id) {
if (!new_tile.data) {
// If we don't find working tile data, we're just going to load it.
if (info.type == SourceType::Vector) {
if (info->type == SourceType::Vector) {
new_tile.data = std::make_shared<VectorTileData>(normalized_id, map, info);
} else if (info.type == SourceType::Raster) {
} else if (info->type == SourceType::Raster) {
new_tile.data = std::make_shared<RasterTileData>(normalized_id, map, info);
} else {
throw std::runtime_error("source type not implemented");
@@ -199,7 +200,7 @@ TileData::State Source::addTile(Map &map, const Tile::ID& id) {
}
double Source::getZoom(const TransformState& state) const {
double offset = std::log(util::tileSize / info.tile_size) / std::log(2);
double offset = std::log(util::tileSize / info->tile_size) / std::log(2);
offset += (state.getPixelRatio() > 1.0 ? 1 :0);
return state.getZoom() + offset;
}
@@ -211,8 +212,8 @@ int32_t Source::coveringZoomLevel(const TransformState& state) const {
std::forward_list<Tile::ID> Source::coveringTiles(const TransformState& state) const {
int32_t z = coveringZoomLevel(state);
if (z < info.min_zoom) return {{}};
if (z > info.max_zoom) z = info.max_zoom;
if (z < info->min_zoom) return {{}};
if (z > info->max_zoom) z = info->max_zoom;
// Map four viewport corners to pixel coordinates
box points = state.cornersToBox(z);
@@ -285,8 +286,8 @@ bool Source::updateTiles(Map &map) {
std::forward_list<Tile::ID> required = coveringTiles(map.getState());
// Determine the overzooming/underzooming amounts.
int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info.min_zoom, info.max_zoom);
int32_t maxCoveringZoom = util::clamp<int32_t>(zoom + 1, info.min_zoom, info.max_zoom);
int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info->min_zoom, info->max_zoom);
int32_t maxCoveringZoom = util::clamp<int32_t>(zoom + 1, info->min_zoom, info->max_zoom);
// Retain is a list of tiles that we shouldn't delete, even if they are not
// the most ideal tile for the current viewport. This may include tiles like
@@ -333,7 +334,7 @@ bool Source::updateTiles(Map &map) {
// Remove all the expired pointers from the set.
util::erase_if(tile_data, [&retain_data](std::pair<const Tile::ID, std::weak_ptr<TileData>> &pair) {
const std::shared_ptr<TileData> tile = pair.second.lock();
const util::ptr<TileData> tile = pair.second.lock();
if (!tile) {
return true;
}

View File

@@ -5,7 +5,7 @@
#include <string>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/filesource.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/std.hpp>
@@ -22,8 +22,8 @@ SpritePosition::SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t
sdf(sdf) {
}
std::shared_ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio, const std::shared_ptr<FileSource> &fileSource) {
std::shared_ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio));
util::ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio, const util::ptr<FileSource> &fileSource) {
util::ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio));
sprite->load(fileSource);
return sprite;
}
@@ -51,7 +51,7 @@ Sprite::operator bool() const {
// Note: This is a separate function that must be called exactly once after creation
// The reason this isn't part of the constructor is that calling shared_from_this() in
// the constructor fails.
void Sprite::load(const std::shared_ptr<FileSource> &fileSource) {
void Sprite::load(const util::ptr<FileSource> &fileSource) {
if (!valid) {
// Treat a non-existent sprite as a successfully loaded empty sprite.
loadedImage = true;
@@ -60,30 +60,30 @@ void Sprite::load(const std::shared_ptr<FileSource> &fileSource) {
return;
}
std::shared_ptr<Sprite> sprite = shared_from_this();
util::ptr<Sprite> sprite = shared_from_this();
fileSource->load(ResourceType::JSON, jsonURL, [sprite](platform::Response *res) {
if (res->code == 200) {
sprite->body.swap(res->body);
fileSource->request(ResourceType::JSON, jsonURL)->onload([sprite](const Response &res) {
if (res.code == 200) {
sprite->body = res.data;
sprite->parseJSON();
sprite->complete();
} else {
Log::Warning(Event::Sprite, "Failed to load sprite info: Error %d: %s", res->code, res->error_message.c_str());
Log::Warning(Event::Sprite, "Failed to load sprite info: Error %d: %s", res.code, res.message.c_str());
if (!sprite->future.valid()) {
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message)));
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
}
}
});
fileSource->load(ResourceType::Image, spriteURL, [sprite](platform::Response *res) {
if (res->code == 200) {
sprite->image.swap(res->body);
fileSource->request(ResourceType::Image, spriteURL)->onload([sprite](const Response &res) {
if (res.code == 200) {
sprite->image = res.data;
sprite->parseImage();
sprite->complete();
} else {
Log::Warning(Event::Sprite, "Failed to load sprite image: Error %d: %s", res->code, res->error_message.c_str());
Log::Warning(Event::Sprite, "Failed to load sprite image: Error %d: %s", res.code, res.message.c_str());
if (!sprite->future.valid()) {
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message)));
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
}
}
});

View File

@@ -4,12 +4,12 @@
#include <mbgl/util/token.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/filesource.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/util/uv_detail.hpp>
using namespace mbgl;
TileData::TileData(Tile::ID id, Map &map, const SourceInfo &source)
TileData::TileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source)
: id(id),
state(State::initial),
map(map),
@@ -29,10 +29,10 @@ const std::string TileData::toString() const {
}
void TileData::request() {
if (source.tiles.empty())
if (source->tiles.empty())
return;
std::string url = source.tiles[(id.x + id.y) % source.tiles.size()];
std::string url = source->tiles[(id.x + id.y) % source->tiles.size()];
url = util::replaceTokens(url, [&](const std::string &token) -> std::string {
if (token == "z") return std::to_string(id.z);
if (token == "x") return std::to_string(id.x);
@@ -45,21 +45,28 @@ void TileData::request() {
// Note: Somehow this feels slower than the change to request_http()
std::weak_ptr<TileData> weak_tile = shared_from_this();
map.getFileSource()->load(ResourceType::Tile, url, [weak_tile, url](platform::Response *res) {
std::shared_ptr<TileData> tile = weak_tile.lock();
req = map.getFileSource()->request(ResourceType::Tile, url);
req->onload([weak_tile, url](const Response &res) {
util::ptr<TileData> tile = weak_tile.lock();
if (!tile || tile->state == State::obsolete) {
// noop. Tile is obsolete and we're now just waiting for the refcount
// to drop to zero for destruction.
} else if (res->code == 200) {
return;
}
// Clear the request object.
tile->req.reset();
if (res.code == 200) {
tile->state = State::loaded;
tile->data.swap(res->body);
tile->data = res.data;
// Schedule tile parsing in another thread
tile->reparse();
} else {
#if defined(DEBUG)
fprintf(stderr, "[%s] tile loading failed: %d, %s\n", url.c_str(), res->code, res->error_message.c_str());
fprintf(stderr, "[%s] tile loading failed: %ld, %s\n", url.c_str(), res.code, res.message.c_str());
#endif
}
});
@@ -68,7 +75,7 @@ void TileData::request() {
void TileData::cancel() {
if (state != State::obsolete) {
state = State::obsolete;
platform::cancel_request_http(req.lock());
req.reset();
}
}
@@ -79,12 +86,12 @@ void TileData::reparse() {
// We're creating a new work request. The work request deletes itself after it executed
// the after work handler
new uv::work<std::shared_ptr<TileData>>(
map.getLoop(),
[](std::shared_ptr<TileData> &tile) {
new uv::work<util::ptr<TileData>>(
map.getWorker(),
[](util::ptr<TileData> &tile) {
tile->parse();
},
[](std::shared_ptr<TileData> &tile) {
[](util::ptr<TileData> &tile) {
tile->afterParse();
tile->map.update();
},

View File

@@ -38,19 +38,26 @@ namespace mbgl {
TileParser::~TileParser() = default;
TileParser::TileParser(const std::string &data, VectorTileData &tile,
const std::shared_ptr<const Style> &style,
const std::shared_ptr<GlyphAtlas> &glyphAtlas,
const std::shared_ptr<GlyphStore> &glyphStore,
const std::shared_ptr<SpriteAtlas> &spriteAtlas,
const std::shared_ptr<Sprite> &sprite)
const util::ptr<const Style> &style_,
const util::ptr<GlyphAtlas> &glyphAtlas_,
const util::ptr<GlyphStore> &glyphStore_,
const util::ptr<SpriteAtlas> &spriteAtlas_,
const util::ptr<Sprite> &sprite_)
: vector_data(pbf((const uint8_t *)data.data(), data.size())),
tile(tile),
style(style),
glyphAtlas(glyphAtlas),
glyphStore(glyphStore),
spriteAtlas(spriteAtlas),
sprite(sprite),
collision(std::make_unique<Collision>(tile.id.z, 4096, tile.source.tile_size, tile.depth)) {
style(style_),
glyphAtlas(glyphAtlas_),
glyphStore(glyphStore_),
spriteAtlas(spriteAtlas_),
sprite(sprite_),
collision(std::make_unique<Collision>(tile.id.z, 4096, tile.source->tile_size, tile.depth)) {
assert(&tile != nullptr);
assert(style);
assert(glyphAtlas);
assert(glyphStore);
assert(spriteAtlas);
assert(sprite);
assert(collision);
}
void TileParser::parse() {
@@ -59,12 +66,12 @@ void TileParser::parse() {
bool TileParser::obsolete() const { return tile.state == TileData::State::obsolete; }
void TileParser::parseStyleLayers(std::shared_ptr<StyleLayerGroup> group) {
void TileParser::parseStyleLayers(util::ptr<StyleLayerGroup> group) {
if (!group) {
return;
}
for (const std::shared_ptr<StyleLayer> &layer_desc : group->layers) {
for (const util::ptr<StyleLayer> &layer_desc : group->layers) {
// Cancel early when parsing.
if (obsolete()) {
return;
@@ -96,14 +103,14 @@ void TileParser::parseStyleLayers(std::shared_ptr<StyleLayerGroup> group) {
}
}
std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bucket_desc) {
std::unique_ptr<Bucket> TileParser::createBucket(util::ptr<StyleBucket> bucket_desc) {
if (!bucket_desc) {
fprintf(stderr, "missing bucket desc\n");
return nullptr;
}
// Skip this bucket if we are to not render this
if (tile.id.z < std::floor(bucket_desc->min_zoom) && std::floor(bucket_desc->min_zoom) < tile.source.max_zoom) return nullptr;
if (tile.id.z < std::floor(bucket_desc->min_zoom) && std::floor(bucket_desc->min_zoom) < tile.source->max_zoom) return nullptr;
if (tile.id.z >= std::ceil(bucket_desc->max_zoom)) return nullptr;
auto layer_it = vector_data.layers.find(bucket_desc->source_layer);
@@ -157,7 +164,7 @@ std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& laye
return obsolete() ? nullptr : std::move(bucket);
}
std::unique_ptr<Bucket> TileParser::createRasterBucket(const std::shared_ptr<Texturepool> &texturepool, const StyleBucketRaster &raster) {
std::unique_ptr<Bucket> TileParser::createRasterBucket(const util::ptr<Texturepool> &texturepool, const StyleBucketRaster &raster) {
std::unique_ptr<RasterBucket> bucket = std::make_unique<RasterBucket>(texturepool, raster);
return obsolete() ? nullptr : std::move(bucket);
}

View File

@@ -466,7 +466,7 @@ bool Transform::needsTransition() const {
void Transform::updateTransitions(const timestamp now) {
uv::writelock lock(mtx);
transitions.remove_if([now](const std::shared_ptr<util::transition> &transition) {
transitions.remove_if([now](const util::ptr<util::transition> &transition) {
return transition->update(now) == util::transition::complete;
});
}

View File

@@ -8,13 +8,13 @@
using namespace mbgl;
VectorTileData::VectorTileData(Tile::ID id, Map &map, const SourceInfo &source)
VectorTileData::VectorTileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source)
: TileData(id, map, source),
depth(id.z >= source.max_zoom ? map.getMaxZoom() - id.z : 1) {
depth(id.z >= source->max_zoom ? map.getMaxZoom() - id.z : 1) {
}
VectorTileData::~VectorTileData() {
std::shared_ptr<GlyphAtlas> glyphAtlas = map.getGlyphAtlas();
util::ptr<GlyphAtlas> glyphAtlas = map.getGlyphAtlas();
if (glyphAtlas) {
glyphAtlas->removeGlyphs(id.to_uint64());
}
@@ -52,7 +52,7 @@ void VectorTileData::afterParse() {
parser.reset();
}
void VectorTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix) {
void VectorTileData::render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) {
if (state == State::parsed && layer_desc->bucket) {
auto databucket_it = buckets.find(layer_desc->bucket->name);
if (databucket_it != buckets.end()) {
@@ -62,7 +62,7 @@ void VectorTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_
}
}
bool VectorTileData::hasData(std::shared_ptr<StyleLayer> layer_desc) const {
bool VectorTileData::hasData(util::ptr<StyleLayer> layer_desc) const {
if (state == State::parsed && layer_desc->bucket) {
auto databucket_it = buckets.find(layer_desc->bucket->name);
if (databucket_it != buckets.end()) {