summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Loer <chris.loer@gmail.com>2017-11-14 15:30:27 -0800
committerChris Loer <chris.loer@mapbox.com>2017-11-17 10:05:15 -0800
commit25cfb5863c9ac3705d2bcf4086c237608264e3ae (patch)
treee142caa7789b0f23e2633ef5f920a869f6e14d91
parentd69c1c4806038fec756672d80cef7691c5280c6a (diff)
downloadqtlocation-mapboxgl-25cfb5863c9ac3705d2bcf4086c237608264e3ae.tar.gz
[core] Symbol cross-fading.
Hold onto tiles after they've been removed from the render tree long enough to run a fade animation on their symbols.
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp23
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp3
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp20
-rw-r--r--src/mbgl/text/placement.cpp19
-rw-r--r--src/mbgl/text/placement.hpp3
-rw-r--r--src/mbgl/tile/geometry_tile.cpp21
-rw-r--r--src/mbgl/tile/geometry_tile.hpp13
-rw-r--r--src/mbgl/tile/tile.hpp14
8 files changed, 112 insertions, 4 deletions
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 032b4558ce..aa138df662 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -339,6 +339,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
} else {
std::sort(sortedTiles.begin(), sortedTiles.end(),
[](const auto& a, const auto& b) { return a.get().id < b.get().id; });
+ // Don't render non-symbol layers for tiles that we're only holding on to for symbol fading
+ sortedTiles.erase(std::remove_if(sortedTiles.begin(), sortedTiles.end(),
+ [](const auto& tile) { return tile.get().tile.holdForFade(); }),
+ sortedTiles.end());
}
std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
@@ -389,6 +393,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
}
placement->setRecent(parameters.timePoint);
+
+ updateFadingTiles();
} else {
placement->setStale();
}
@@ -754,10 +760,27 @@ bool Renderer::Impl::hasTransitions(TimePoint timePoint) const {
if (placement->hasTransitions(timePoint)) {
return true;
}
+
+ if (fadingTiles) {
+ return true;
+ }
return false;
}
+void Renderer::Impl::updateFadingTiles() {
+ fadingTiles = false;
+ for (auto& source : renderSources) {
+ for (auto& renderTile : source.second->getRenderTiles()) {
+ Tile& tile = renderTile.get().tile;
+ if (tile.holdForFade()) {
+ fadingTiles = true;
+ tile.performedFadePlacement();
+ }
+ }
+ }
+}
+
bool Renderer::Impl::isLoaded() const {
for (const auto& entry: renderSources) {
if (!entry.second->isLoaded()) {
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 32e2dc99f2..4f8139791c 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -74,6 +74,8 @@ private:
void onTileChanged(RenderSource&, const OverscaledTileID&) override;
void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
+ void updateFadingTiles();
+
friend class Renderer;
RendererBackend& backend;
@@ -113,6 +115,7 @@ private:
std::unique_ptr<Placement> placement;
bool contextLost = false;
+ bool fadingTiles = false;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index fae16c9ce6..c1566d12a5 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -148,9 +148,17 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
}
return tiles.emplace(tileID, std::move(tile)).first->second.get();
};
+
+ std::map<UnwrappedTileID, Tile*> previouslyRenderedTiles;
+ for (auto& renderTile : renderTiles) {
+ previouslyRenderedTiles[renderTile.id] = &renderTile.tile;
+ }
+
auto renderTileFn = [&](const UnwrappedTileID& tileID, Tile& tile) {
renderTiles.emplace_back(tileID, tile);
rendered.emplace(tileID);
+ previouslyRenderedTiles.erase(tileID); // Still rendering this tile, no need for special fading logic.
+ tile.markRenderedIdeal();
};
renderTiles.clear();
@@ -162,6 +170,18 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn,
idealTiles, zoomRange, tileZoom);
+
+ for (auto previouslyRenderedTile : previouslyRenderedTiles) {
+ Tile& tile = *previouslyRenderedTile.second;
+ tile.markRenderedPreviously();
+ if (tile.holdForFade()) {
+ // Since it was rendered in the last frame, we know we have it
+ // Don't mark the tile "Required" to avoid triggering a new network request
+ retainTileFn(tile, TileNecessity::Optional);
+ renderTiles.emplace_back(previouslyRenderedTile.first, tile);
+ rendered.emplace(previouslyRenderedTile.first);
+ }
+ }
if (type != SourceType::Annotations) {
size_t conservativeCacheSize =
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 85f6385ce6..9284e213c2 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -46,7 +46,6 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri
std::unordered_set<uint32_t> seenCrossTileIDs;
for (RenderTile& renderTile : symbolLayer.renderTiles) {
-
if (!renderTile.tile.isRenderable()) {
continue;
}
@@ -78,7 +77,7 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri
state,
pixelsToTileUnits);
- placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs);
+ placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs, renderTile.tile.holdForFade());
}
}
@@ -90,7 +89,8 @@ void Placement::placeLayerBucket(
const float scale,
const float textPixelRatio,
const bool showCollisionBoxes,
- std::unordered_set<uint32_t>& seenCrossTileIDs) {
+ std::unordered_set<uint32_t>& seenCrossTileIDs,
+ const bool holdingForFade) {
auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom());
auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom());
@@ -101,6 +101,13 @@ void Placement::placeLayerBucket(
for (auto& symbolInstance : bucket.symbolInstances) {
if (seenCrossTileIDs.count(symbolInstance.crossTileID) == 0) {
+ if (holdingForFade) {
+ // Mark all symbols from this tile as "not placed", but don't add to seenCrossTileIDs, because we don't
+ // know yet if we have a duplicate in a parent tile that _should_ be placed.
+ placements.emplace(symbolInstance.crossTileID, JointPlacement(false, false, false));
+ continue;
+ }
+
bool placeText = false;
bool placeIcon = false;
bool offscreen = true;
@@ -152,6 +159,12 @@ void Placement::placeLayerBucket(
assert(symbolInstance.crossTileID != 0);
+ if (placements.find(symbolInstance.crossTileID) != placements.end()) {
+ // If there's a previous placement with this ID, it comes from a tile that's fading out
+ // Erase it so that the placement result from the non-fading tile supersedes it
+ placements.erase(symbolInstance.crossTileID);
+ }
+
placements.emplace(symbolInstance.crossTileID, JointPlacement(placeText, placeIcon, offscreen));
seenCrossTileIDs.insert(symbolInstance.crossTileID);
}
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
index c6d1f259a5..bcc20f15a4 100644
--- a/src/mbgl/text/placement.hpp
+++ b/src/mbgl/text/placement.hpp
@@ -70,7 +70,8 @@ private:
const float scale,
const float pixelRatio,
const bool showCollisionBoxes,
- std::unordered_set<uint32_t>& seenCrossTileIDs);
+ std::unordered_set<uint32_t>& seenCrossTileIDs,
+ const bool holdingForFade);
void updateBucketOpacities(SymbolBucket&, std::set<uint32_t>&);
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 66778fa2b7..701e7cf2d6 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -294,4 +294,25 @@ void GeometryTile::resetCrossTileIDs() {
}
}
+bool GeometryTile::holdForFade() const {
+ return mode == MapMode::Continuous &&
+ (fadeState == FadeState::NeedsFirstPlacement || fadeState == FadeState::NeedsSecondPlacement);
+}
+
+void GeometryTile::markRenderedIdeal() {
+ fadeState = FadeState::Loaded;
+}
+void GeometryTile::markRenderedPreviously() {
+ if (fadeState == FadeState::Loaded) {
+ fadeState = FadeState::NeedsFirstPlacement;
+ }
+}
+void GeometryTile::performedFadePlacement() {
+ if (fadeState == FadeState::NeedsFirstPlacement) {
+ fadeState = FadeState::NeedsSecondPlacement;
+ } else if (fadeState == FadeState::NeedsSecondPlacement) {
+ fadeState = FadeState::CanRemove;
+ }
+}
+
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 442d84244e..6f871819a4 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -97,6 +97,11 @@ public:
void resetCrossTileIDs() override;
+ bool holdForFade() const override;
+ void markRenderedIdeal() override;
+ void markRenderedPreviously() override;
+ void performedFadePlacement() override;
+
protected:
const GeometryTileData* getData() {
return data.get();
@@ -130,7 +135,15 @@ private:
const MapMode mode;
bool showCollisionBoxes;
+
+ enum class FadeState {
+ Loaded,
+ NeedsFirstPlacement,
+ NeedsSecondPlacement,
+ CanRemove
+ };
+ FadeState fadeState = FadeState::Loaded;
public:
optional<gl::Texture> glyphAtlasTexture;
optional<gl::Texture> iconAtlasTexture;
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index b4b50b93ee..1186b74111 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -95,6 +95,20 @@ public:
return loaded && !pending;
}
+ // "holdForFade" is used to keep tiles in the render tree after they're no longer
+ // ideal tiles in order to allow symbols to fade out
+ virtual bool holdForFade() const {
+ return false;
+ }
+ // Set whenever this tile is used as an ideal tile
+ virtual void markRenderedIdeal() {}
+ // Set when the tile is removed from the ideal render set but may still be held for fading
+ virtual void markRenderedPreviously() {}
+ // Placement operation performed while this tile is fading
+ // We hold onto a tile for two placements: fading starts with the first placement
+ // and will have time to finish by the second placement.
+ virtual void performedFadePlacement() {}
+
virtual void resetCrossTileIDs() {};
void dumpDebugLogs() const;