[core] Switch from background to foreground placement

- Background placement code now just generates static symbol buffers
 - Don't render GeometryTiles until their symbols are loaded. This is necessary for the CrossTileSymbolIndex to successfully prevent flicker.
 - SymbolInstances are transferred to SymbolBucket for use on foreground during collision detection
 - Symbols are sorted on foreground by sorting their index buffer but leaving vertex buffers intact (only works within one segment)
 - Vertical glyphs are generated at same time as horizontal glyphs. `reprojectLineLabels` chooses which one to use at render time and hides the other.
 - Icons are now always represented with a single collision box, even if they're placed along a line (this means their rotation alignment may be wrong, but the approach of representing them with multiple collision boxes wasn't very accurate either).
 - Generate vertices for new debug collision boxes and collision circles
 - Only add symbols within tile boundaries (reduces work, avoids double-draw)
 - Update symbol_projection.cpp to support line label projection calls from CollisionIndex.
This commit is contained in:
Chris Loer
2017-11-09 13:24:43 -08:00
committed by Chris Loer
parent 9a5b2fdfc3
commit c0cb210ddc
21 changed files with 696 additions and 430 deletions

View File

@@ -15,7 +15,6 @@
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/util/logging.hpp>
@@ -33,7 +32,7 @@ using namespace style;
GeometryTile's 'correlationID' is used for ensuring the tile will be flagged
as non-pending only when the placement coming from the last operation (as in
'setData', 'setLayers', 'setPlacementConfig') occurs. This is important for
'setData', 'setLayers', 'setShowCollisionBoxes') occurs. This is important for
still mode rendering as we want to render only when all layout and placement
operations are completed.
@@ -52,13 +51,15 @@ GeometryTile::GeometryTile(const OverscaledTileID& id_,
worker(parameters.workerScheduler,
ActorRef<GeometryTile>(*this, mailbox),
id_,
sourceID,
obsolete,
parameters.mode,
parameters.pixelRatio),
parameters.pixelRatio,
parameters.debugOptions & MapDebugOptions::Collision),
glyphManager(parameters.glyphManager),
imageManager(parameters.imageManager),
lastYStretch(1.0f),
mode(parameters.mode) {
mode(parameters.mode),
showCollisionBoxes(parameters.debugOptions & MapDebugOptions::Collision) {
}
GeometryTile::~GeometryTile() {
@@ -89,25 +90,6 @@ void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) {
worker.invoke(&GeometryTileWorker::setData, std::move(data_), correlationID);
}
void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) {
if (requestedConfig == desiredConfig) {
return;
}
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
pending = true;
++correlationID;
requestedConfig = desiredConfig;
invokePlacement();
}
void GeometryTile::invokePlacement() {
if (requestedConfig) {
worker.invoke(&GeometryTileWorker::setPlacementConfig, *requestedConfig, correlationID);
}
}
void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers) {
// Mark the tile as pending again if it was complete before to prevent signaling a complete
@@ -134,14 +116,22 @@ void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers)
worker.invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID);
}
void GeometryTile::setShowCollisionBoxes(const bool showCollisionBoxes_) {
if (showCollisionBoxes != showCollisionBoxes_) {
showCollisionBoxes = showCollisionBoxes_;
++correlationID;
worker.invoke(&GeometryTileWorker::setShowCollisionBoxes, showCollisionBoxes, correlationID);
}
}
void GeometryTile::onLayout(LayoutResult result, const uint64_t resultCorrelationID) {
loaded = true;
renderable = true;
// Don't mark ourselves loaded or renderable until the first successful placement
// TODO: Ideally we'd render this tile without symbols as long as this tile wasn't
// replacing a tile at a different zoom that _did_ have symbols.
(void)resultCorrelationID;
nonSymbolBuckets = std::move(result.nonSymbolBuckets);
featureIndex = std::move(result.featureIndex);
data = std::move(result.tileData);
collisionTile.reset();
observer->onTileChanged(*this);
}
@@ -152,16 +142,13 @@ void GeometryTile::onPlacement(PlacementResult result, const uint64_t resultCorr
pending = false;
}
symbolBuckets = std::move(result.symbolBuckets);
collisionTile = std::move(result.collisionTile);
if (result.glyphAtlasImage) {
glyphAtlasImage = std::move(*result.glyphAtlasImage);
}
if (result.iconAtlasImage) {
iconAtlasImage = std::move(*result.iconAtlasImage);
}
if (collisionTile.get()) {
lastYStretch = collisionTile->yStretch;
}
observer->onTileChanged(*this);
}
@@ -231,7 +218,8 @@ void GeometryTile::queryRenderedFeatures(
const GeometryCoordinates& queryGeometry,
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) {
const RenderedQueryOptions& options,
const CollisionIndex& collisionIndex) {
if (!featureIndex || !data) return;
@@ -251,9 +239,10 @@ void GeometryTile::queryRenderedFeatures(
std::pow(2, transformState.getZoom() - id.overscaledZ),
options,
*data,
id.canonical,
id.toUnwrapped(),
sourceID,
layers,
collisionTile.get(),
collisionIndex,
additionalRadius);
}
@@ -293,11 +282,16 @@ void GeometryTile::querySourceFeatures(
}
}
float GeometryTile::yStretch() const {
// collisionTile gets reset in onLayout but we don't clear the symbolBuckets
// until a new placement result comes along, so keep the yStretch value in
// case we need to render them.
return lastYStretch;
void GeometryTile::resetCrossTileIDs() {
for (auto& bucket : symbolBuckets) {
auto symbolBucket = dynamic_cast<SymbolBucket*>(bucket.second.get());
if (symbolBucket && symbolBucket->bucketInstanceId) {
symbolBucket->bucketInstanceId = 0;
for (auto& symbolInstance : symbolBucket->symbolInstances) {
symbolInstance.crossTileID = 0;
}
}
}
}
} // namespace mbgl