[core] Split MapMode::Still into Static and Tile

`Tile` makes sure the symbols in the resulting tile are tileable while
symbols in `Still` match rendering in `Continuous` mode.
This commit is contained in:
Ansis Brammanis
2017-11-10 11:32:37 -05:00
committed by Chris Loer
parent 5bdee52e5c
commit 22c07596a0
29 changed files with 69 additions and 57 deletions

View File

@@ -34,7 +34,7 @@ public:
DefaultFileSource fileSource{ "benchmark/fixtures/api/cache.db", "." };
ThreadPool threadPool{ 4 };
HeadlessFrontend frontend { { 1000, 1000 }, 1, fileSource, threadPool };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, fileSource, threadPool, MapMode::Still };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, fileSource, threadPool, MapMode::Static};
ScreenBox box{{ 0, 0 }, { 1000, 1000 }};
};

View File

@@ -41,7 +41,7 @@ static void prepare(Map& map, optional<std::string> json = {}) {
static void API_renderStill_reuse_map(::benchmark::State& state) {
RenderBenchmark bench;
HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.fileSource, bench.threadPool };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, bench.fileSource, bench.threadPool, MapMode::Still };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, bench.fileSource, bench.threadPool, MapMode::Static};
prepare(map);
while (state.KeepRunning()) {
@@ -52,7 +52,7 @@ static void API_renderStill_reuse_map(::benchmark::State& state) {
static void API_renderStill_reuse_map_switch_styles(::benchmark::State& state) {
RenderBenchmark bench;
HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.fileSource, bench.threadPool };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, bench.fileSource, bench.threadPool, MapMode::Still };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, bench.fileSource, bench.threadPool, MapMode::Static};
while (state.KeepRunning()) {
prepare(map, { "{}" });
@@ -67,7 +67,7 @@ static void API_renderStill_recreate_map(::benchmark::State& state) {
while (state.KeepRunning()) {
HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.fileSource, bench.threadPool };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, bench.fileSource, bench.threadPool, MapMode::Still };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, bench.fileSource, bench.threadPool, MapMode::Static};
prepare(map);
frontend.render(map);
}

View File

@@ -83,7 +83,7 @@ int main(int argc, char *argv[]) {
ThreadPool threadPool(4);
HeadlessFrontend frontend({ width, height }, pixelRatio, fileSource, threadPool);
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, threadPool, MapMode::Still);
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, threadPool, MapMode::Static);
if (style_path.find("://") == std::string::npos) {
style_path = std::string("file://") + style_path;

View File

@@ -11,7 +11,8 @@ using EnumType = uint32_t;
enum class MapMode : EnumType {
Continuous, // continually updating map
Still, // a once-off still image
Static, // a once-off still image of an arbitrary viewport
Tile // a once-off still image of a single tile
};
// We can choose to constrain the map both horizontally or vertically, or only

View File

@@ -50,7 +50,7 @@ MapSnapshotter::Impl::Impl(FileSource& fileSource,
const optional<LatLngBounds> region,
const optional<std::string> programCacheDir)
: frontend(size, pixelRatio, fileSource, scheduler, programCacheDir)
, map(frontend, MapObserver::nullObserver(), size, pixelRatio, fileSource, scheduler, MapMode::Still) {
, map(frontend, MapObserver::nullObserver(), size, pixelRatio, fileSource, scheduler, MapMode::Static) {
map.getStyle().loadURL(styleURL);

View File

@@ -1,3 +1,6 @@
# master
- The `Map` constructor now accepts a `mode` option which can be either `"static"` (default) or `"tile"`. It must be set to `"tile"` when rendering individual tiles in order for the symbols to match across tiles.
# 3.5.8 - October 19, 2017
- Fixes an issue that causes memory leaks when not deleting the frontend object
in NodeMap::release()

View File

@@ -548,7 +548,7 @@ void NodeMap::cancel() {
frontend = std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size{ 256, 256 }, pixelRatio, *this, threadpool);
map = std::make_unique<mbgl::Map>(*frontend, mapObserver, frontend->getSize(), pixelRatio,
*this, threadpool, mbgl::MapMode::Still);
*this, threadpool, mode);
// FIXME: Reload the style after recreating the map. We need to find
// a better way of canceling an ongoing rendering on the core level
@@ -1074,6 +1074,15 @@ NodeMap::NodeMap(v8::Local<v8::Object> options)
->NumberValue()
: 1.0;
}())
, mode([&] {
Nan::HandleScope scope;
if (Nan::Has(options, Nan::New("mode").ToLocalChecked()).FromJust() &&
std::string(*v8::String::Utf8Value(Nan::Get(options, Nan::New("mode").ToLocalChecked()).ToLocalChecked()->ToString())) == "tile") {
return mbgl::MapMode::Tile;
} else {
return mbgl::MapMode::Static;
}
}())
, mapObserver(NodeMapObserver())
, frontend(std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size { 256, 256 }, pixelRatio, *this, threadpool))
, map(std::make_unique<mbgl::Map>(*frontend,
@@ -1082,7 +1091,7 @@ NodeMap::NodeMap(v8::Local<v8::Object> options)
pixelRatio,
*this,
threadpool,
mbgl::MapMode::Still)),
mode)),
async(new uv_async_t) {
async->data = this;

View File

@@ -74,6 +74,7 @@ public:
std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback);
const float pixelRatio;
mbgl::MapMode mode;
NodeThreadPool threadpool;
NodeMapObserver mapObserver;
std::unique_ptr<mbgl::HeadlessFrontend> frontend;

View File

@@ -14,21 +14,25 @@ mbgl.on('message', function(msg) {
var maps = new Map();
module.exports = function (style, options, callback) {
var tileMode = options.mapMode === 'tile';
if (options.recycleMap) {
if (maps.has(options.pixelRatio)) {
var map = maps.get(options.pixelRatio);
var key = options.pixelRatio + '/' + tileMode;
if (maps.has(key)) {
var map = maps.get(key);
map.request = mapRequest;
} else {
maps.set(options.pixelRatio, new mbgl.Map({
maps.set(key, new mbgl.Map({
ratio: options.pixelRatio,
request: mapRequest
request: mapRequest,
mode: options.mapMode
}));
var map = maps.get(options.pixelRatio);
var map = maps.get(key);
}
} else {
var map = new mbgl.Map({
ratio: options.pixelRatio,
request: mapRequest
request: mapRequest,
mode: options.mapMode
});
}

View File

@@ -314,9 +314,7 @@ void SymbolLayout::addFeature(const std::size_t index,
if (avoidEdges && !inside) return;
// TODO set this to make api-gl work
const bool singleTileMode = false && mode == MapMode::Still;
if (singleTileMode || withinPlus0) {
if (mode == MapMode::Tile || withinPlus0) {
symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon,
layout.evaluate(zoom, feature), layoutTextSize,
symbolInstances.size(),

View File

@@ -149,8 +149,8 @@ void Map::renderStill(StillImageCallback callback) {
return;
}
if (impl->mode != MapMode::Still) {
callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")));
if (impl->mode != MapMode::Static && impl->mode != MapMode::Tile) {
callback(std::make_exception_ptr(util::MisuseException("Map is not in static or tile image render modes")));
return;
}
@@ -794,7 +794,7 @@ void Map::Impl::onStyleError(std::exception_ptr error) {
}
void Map::Impl::onResourceError(std::exception_ptr error) {
if (mode == MapMode::Still && stillImageRequest) {
if (mode != MapMode::Continuous && stillImageRequest) {
auto request = std::move(stillImageRequest);
request->callback(error);
}

View File

@@ -49,7 +49,7 @@ void CircleBucket::addFeature(const GeometryTileFeature& feature,
// Do not include points that are outside the tile boundaries.
// Include all points in Still mode. You need to include points from
// neighbouring tiles so that they are not clipped at tile boundaries.
if ((mode != MapMode::Still) &&
if ((mode == MapMode::Continuous) &&
(x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) continue;
if (segments.empty() || segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {

View File

@@ -63,7 +63,7 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) {
parameters.context,
gl::Triangles(),
parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
parameters.mapMode == MapMode::Still
parameters.mapMode != MapMode::Continuous
? parameters.stencilModeForClipping(tile.clip)
: gl::StencilMode::disabled(),
parameters.colorModeForRenderPass(),

View File

@@ -88,18 +88,13 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
const auto& binders,
const auto& paintProperties)
{
// We clip symbols to their tile extent in still mode.
const bool needsClipping = false; // TODO parameters.mapMode == MapMode::Still;
program.get(paintProperties).draw(
parameters.context,
gl::Triangles(),
values_.pitchAlignment == AlignmentType::Map
? parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly)
: gl::DepthMode::disabled(),
needsClipping
? parameters.stencilModeForClipping(tile.clip)
: gl::StencilMode::disabled(),
gl::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
std::move(uniformValues),
*buffers.vertexBuffer,

View File

@@ -59,7 +59,7 @@ Renderer::Impl::Impl(RendererBackend& backend_,
, layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>())
, renderLight(makeMutable<Light::Impl>())
, crossTileSymbolIndex(std::make_unique<CrossTileSymbolIndex>())
, placement(std::make_unique<Placement>(TransformState{}, MapMode::Still)) {
, placement(std::make_unique<Placement>(TransformState{}, MapMode::Static)) {
glyphManager->setObserver(this);
}
@@ -83,7 +83,7 @@ void Renderer::Impl::setObserver(RendererObserver* observer_) {
}
void Renderer::Impl::render(const UpdateParameters& updateParameters) {
if (updateParameters.mode == MapMode::Still) {
if (updateParameters.mode != MapMode::Continuous) {
// Don't load/render anyting in still mode until explicitly requested.
if (!updateParameters.stillImageRequest) {
return;
@@ -260,7 +260,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
};
bool loaded = updateParameters.styleLoaded && isLoaded();
if (updateParameters.mode == MapMode::Still && !loaded) {
if (updateParameters.mode != MapMode::Continuous && !loaded) {
return;
}
@@ -355,10 +355,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
sortedTilesForInsertion.emplace_back(tile);
tile.used = true;
// We only need clipping when we're _not_ drawing a symbol layer. The only exception
// for symbol layers is when we're rendering still images. See render_symbol_layer.cpp
// for the exception we make there.
if (!symbolLayer || parameters.mapMode == MapMode::Still) {
// We only need clipping when we're _not_ drawing a symbol layer.
if (!symbolLayer) {
tile.needsClipping = true;
}
}
@@ -368,7 +366,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
}
bool symbolBucketsChanged = false;
if (parameters.mapMode == MapMode::Still) {
if (parameters.mapMode != MapMode::Continuous) {
// TODO: Think about right way for symbol index to handle still rendering
crossTileSymbolIndex->reset();
}

View File

@@ -154,7 +154,9 @@ bool Placement::commit(const Placement& prevPlacement, TimePoint now) {
bool placementChanged = false;
float increment = mapMode == MapMode::Still ? 1.0 : std::chrono::duration<float>(commitTime - prevPlacement.commitTime) / Duration(std::chrono::milliseconds(300));
float increment = mapMode == MapMode::Continuous ?
std::chrono::duration<float>(commitTime - prevPlacement.commitTime) / Duration(std::chrono::milliseconds(300)) :
1.0;
// add the opacities from the current placement, and copy their current values from the previous placement
for (auto& placementPair : placements) {
@@ -275,10 +277,11 @@ JointOpacityState Placement::getOpacity(uint32_t crossTileSymbolID) const {
}
float Placement::symbolFadeChange(TimePoint now) const {
if (mapMode == MapMode::Still) {
if (mapMode == MapMode::Continuous) {
return std::chrono::duration<float>(now - commitTime) / Duration(std::chrono::milliseconds(300));
} else {
return 1.0;
}
return std::chrono::duration<float>(now - commitTime) / Duration(std::chrono::milliseconds(300));
}
bool Placement::hasTransitions(TimePoint now) const {

View File

@@ -32,7 +32,7 @@ public:
float pixelRatio { 1 };
HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource,
threadPool, MapMode::Still };
threadPool, MapMode::Static};
void checkRendering(const char * name) {
test::checkImage(std::string("test/fixtures/annotations/") + name,

View File

@@ -27,7 +27,7 @@ TEST(API, RenderWithoutCallback) {
HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(),
pixelRatio, fileSource, threadPool, MapMode::Still);
pixelRatio, fileSource, threadPool, MapMode::Static);
map->renderStill(nullptr);
// Force Map thread to join.

View File

@@ -90,7 +90,7 @@ TEST(CustomLayer, Basic) {
float pixelRatio { 1 };
HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource,
threadPool, MapMode::Still);
threadPool, MapMode::Static);
map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json"));
map.setLatLngZoom({ 37.8, -122.5 }, 10);
map.getStyle().addLayer(std::make_unique<CustomLayer>(

View File

@@ -32,7 +32,7 @@ public:
float pixelRatio { 1 };
HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource,
threadPool, MapMode::Still };
threadPool, MapMode::Static};
};
} // end namespace

View File

@@ -29,7 +29,7 @@ TEST(API, RecycleMapUpdateImages) {
HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(),
pixelRatio, fileSource, threadPool, MapMode::Still);
pixelRatio, fileSource, threadPool, MapMode::Static);
EXPECT_TRUE(map);

View File

@@ -30,7 +30,7 @@ TEST(API, ZoomHistory) {
HeadlessFrontend frontend { pixelRatio, fileSource, threadPool };
auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(),
pixelRatio, fileSource, threadPool, MapMode::Still);
pixelRatio, fileSource, threadPool, MapMode::Static);
EXPECT_TRUE(map);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -47,7 +47,7 @@ TEST(Buckets, CircleBucket) {
BackendScope scope { backend };
gl::Context context;
CircleBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} };
CircleBucket bucket { { {0, 0, 0}, MapMode::Static, 1.0 }, {} };
ASSERT_FALSE(bucket.hasData());
ASSERT_FALSE(bucket.needsUpload());
@@ -66,7 +66,7 @@ TEST(Buckets, FillBucket) {
BackendScope scope { backend };
gl::Context context;
FillBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {} };
FillBucket bucket { { {0, 0, 0}, MapMode::Static, 1.0 }, {} };
ASSERT_FALSE(bucket.hasData());
ASSERT_FALSE(bucket.needsUpload());
@@ -84,7 +84,7 @@ TEST(Buckets, LineBucket) {
BackendScope scope { backend };
gl::Context context;
LineBucket bucket { { {0, 0, 0}, MapMode::Still, 1.0 }, {}, {} };
LineBucket bucket { { {0, 0, 0}, MapMode::Static, 1.0 }, {}, {} };
ASSERT_FALSE(bucket.hasData());
ASSERT_FALSE(bucket.needsUpload());

View File

@@ -89,7 +89,7 @@ TEST(GLContextMode, Shared) {
HeadlessFrontend frontend { pixelRatio, fileSource, threadPool, {}, GLContextMode::Shared };
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, threadPool, MapMode::Still);
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, threadPool, MapMode::Static);
map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json"));
map.setLatLngZoom({ 37.8, -122.5 }, 10);

View File

@@ -72,14 +72,14 @@ public:
HeadlessFrontend frontend;
Map map;
MapTest(float pixelRatio = 1, MapMode mode = MapMode::Still)
MapTest(float pixelRatio = 1, MapMode mode = MapMode::Static)
: frontend(pixelRatio, fileSource, threadPool)
, map(frontend, observer, frontend.getSize(), pixelRatio, fileSource, threadPool, mode) {
}
template <typename T = FileSource>
MapTest(const std::string& cachePath, const std::string& assetRoot,
float pixelRatio = 1, MapMode mode = MapMode::Still,
float pixelRatio = 1, MapMode mode = MapMode::Static,
typename std::enable_if<std::is_same<T, DefaultFileSource>::value>::type* = 0)
: fileSource { cachePath, assetRoot }
, frontend(pixelRatio, fileSource, threadPool)

View File

@@ -23,7 +23,7 @@ TEST(Map, PrefetchTiles) {
ThreadPool threadPool(4);
StubFileSource fileSource;
HeadlessFrontend frontend { { 512, 512 }, 1, fileSource, threadPool };
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), 1, fileSource, threadPool, MapMode::Still);
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), 1, fileSource, threadPool, MapMode::Static);
std::vector<int> tiles;

View File

@@ -72,7 +72,7 @@ TEST(Memory, Vector) {
HeadlessFrontend frontend { { 256, 256 }, ratio, test.fileSource, test.threadPool };
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), ratio, test.fileSource,
test.threadPool, MapMode::Still);
test.threadPool, MapMode::Static);
map.setZoom(16); // more map features
map.getStyle().loadURL("mapbox://streets");
@@ -85,7 +85,7 @@ TEST(Memory, Raster) {
HeadlessFrontend frontend { { 256, 256 }, ratio, test.fileSource, test.threadPool };
Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), ratio, test.fileSource,
test.threadPool, MapMode::Still);
test.threadPool, MapMode::Static);
map.getStyle().loadURL("mapbox://satellite");
frontend.render(map);
@@ -122,7 +122,7 @@ TEST(Memory, Footprint) {
public:
FrontendAndMap(MemoryTest& test_, const char* style)
: frontend(Size{ 256, 256 }, 2, test_.fileSource, test_.threadPool)
, map(frontend, MapObserver::nullObserver(), frontend.getSize(), 2, test_.fileSource, test_.threadPool, MapMode::Still) {
, map(frontend, MapObserver::nullObserver(), frontend.getSize(), 2, test_.fileSource, test_.threadPool, MapMode::Static) {
map.setZoom(16);
map.getStyle().loadURL(style);
frontend.render(map);