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:
219
src/map/map.cpp
219
src/map/map.cpp
@@ -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.
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user