summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <tmpsantos@gmail.com>2017-10-18 13:11:31 -0700
committerThiago Marcos P. Santos <tmpsantos@gmail.com>2017-10-18 14:58:29 -0700
commit90a7cf87a32f6787e57e3852ac9d3015d8112621 (patch)
tree9f4d18736ee976b0071b54dd0610b8ac0a22a14f /src
parent1c633072fcea7ad153ab6f8ec40dd72d83541ead (diff)
downloadqtlocation-mapboxgl-90a7cf87a32f6787e57e3852ac9d3015d8112621.tar.gz
Bump Mapbox GL Native
mapbox-gl-native @ 10f7af19ce1ec61f37459f9cd75e2a0c89a0c790
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/algorithm/generate_clip_ids_impl.hpp2
-rw-r--r--src/mbgl/algorithm/update_renderables.hpp25
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp38
-rw-r--r--src/mbgl/annotation/annotation_manager.hpp11
-rw-r--r--src/mbgl/annotation/annotation_tile.cpp3
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp2
-rw-r--r--src/mbgl/annotation/render_annotation_source.cpp4
-rw-r--r--src/mbgl/annotation/render_annotation_source.hpp4
-rw-r--r--src/mbgl/geometry/feature_index.cpp97
-rw-r--r--src/mbgl/geometry/feature_index.hpp9
-rw-r--r--src/mbgl/gl/context.cpp21
-rw-r--r--src/mbgl/gl/context.hpp8
-rw-r--r--src/mbgl/gl/renderbuffer.hpp16
-rw-r--r--src/mbgl/gl/value.cpp6
-rw-r--r--src/mbgl/gl/value.hpp2
-rw-r--r--src/mbgl/layout/symbol_layout.cpp5
-rw-r--r--src/mbgl/layout/symbol_projection.cpp72
-rw-r--r--src/mbgl/map/map.cpp161
-rw-r--r--src/mbgl/map/transform.cpp26
-rw-r--r--src/mbgl/map/transform.hpp8
-rw-r--r--src/mbgl/map/transform_state.cpp11
-rw-r--r--src/mbgl/map/transform_state.hpp5
-rw-r--r--src/mbgl/map/zoom_history.hpp2
-rw-r--r--src/mbgl/programs/attributes.hpp2
-rw-r--r--src/mbgl/programs/line_program.cpp2
-rw-r--r--src/mbgl/programs/line_program.hpp3
-rw-r--r--src/mbgl/renderer/image_manager.cpp21
-rw-r--r--src/mbgl/renderer/image_manager.hpp8
-rw-r--r--src/mbgl/renderer/layers/render_custom_layer.cpp8
-rw-r--r--src/mbgl/renderer/layers/render_custom_layer.hpp5
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp194
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp4
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.cpp4
-rw-r--r--src/mbgl/renderer/paint_parameters.cpp17
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp8
-rw-r--r--src/mbgl/renderer/render_pass.hpp1
-rw-r--r--src/mbgl/renderer/render_source.hpp3
-rw-r--r--src/mbgl/renderer/render_static_data.hpp5
-rw-r--r--src/mbgl/renderer/render_tile.hpp1
-rw-r--r--src/mbgl/renderer/renderer.cpp12
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp586
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp70
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp24
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.hpp4
-rw-r--r--src/mbgl/renderer/sources/render_image_source.cpp2
-rw-r--r--src/mbgl/renderer/sources/render_image_source.hpp4
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.cpp2
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.hpp4
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.cpp4
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.hpp4
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp47
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp8
-rw-r--r--src/mbgl/renderer/update_parameters.hpp4
-rw-r--r--src/mbgl/shaders/line.cpp9
-rw-r--r--src/mbgl/shaders/line_pattern.cpp9
-rw-r--r--src/mbgl/shaders/line_sdf.cpp9
-rw-r--r--src/mbgl/storage/resource.cpp22
-rw-r--r--src/mbgl/style/function/categorical_stops.cpp2
-rw-r--r--src/mbgl/style/function/identity_stops.cpp4
-rw-r--r--src/mbgl/style/image_impl.hpp1
-rw-r--r--src/mbgl/style/layers/custom_layer.cpp11
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.cpp2
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp34
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp14
-rw-r--r--src/mbgl/style/observer.hpp3
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp2
-rw-r--r--src/mbgl/style/sources/image_source.cpp2
-rw-r--r--src/mbgl/style/style_impl.cpp17
-rw-r--r--src/mbgl/style/types.cpp20
-rw-r--r--src/mbgl/text/glyph_manager.cpp11
-rw-r--r--src/mbgl/text/glyph_manager.hpp2
-rw-r--r--src/mbgl/text/placement_config.hpp6
-rw-r--r--src/mbgl/text/shaping.cpp106
-rw-r--r--src/mbgl/text/shaping.hpp7
-rw-r--r--src/mbgl/tile/geojson_tile.cpp97
-rw-r--r--src/mbgl/tile/geojson_tile.hpp2
-rw-r--r--src/mbgl/tile/geojson_tile_data.hpp94
-rw-r--r--src/mbgl/tile/geometry_tile.cpp61
-rw-r--r--src/mbgl/tile/geometry_tile.hpp31
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp30
-rw-r--r--src/mbgl/tile/geometry_tile_worker.hpp3
-rw-r--r--src/mbgl/tile/raster_tile.cpp26
-rw-r--r--src/mbgl/tile/raster_tile.hpp13
-rw-r--r--src/mbgl/tile/raster_tile_worker.cpp8
-rw-r--r--src/mbgl/tile/raster_tile_worker.hpp2
-rw-r--r--src/mbgl/tile/tile.cpp4
-rw-r--r--src/mbgl/tile/tile.hpp18
-rw-r--r--src/mbgl/tile/tile_id_hash.cpp29
-rw-r--r--src/mbgl/tile/tile_loader.hpp12
-rw-r--r--src/mbgl/tile/tile_loader_impl.hpp61
-rw-r--r--src/mbgl/tile/vector_tile.cpp8
-rw-r--r--src/mbgl/tile/vector_tile.hpp7
-rw-r--r--src/mbgl/util/constants.cpp2
-rw-r--r--src/mbgl/util/http_timeout.cpp2
-rw-r--r--src/mbgl/util/i18n.cpp2
-rw-r--r--src/mbgl/util/mapbox.cpp6
-rw-r--r--src/mbgl/util/mapbox.hpp4
-rw-r--r--src/mbgl/util/math.hpp4
-rw-r--r--src/mbgl/util/offscreen_texture.cpp32
-rw-r--r--src/mbgl/util/offscreen_texture.hpp11
-rw-r--r--src/mbgl/util/tile_cover.cpp25
-rw-r--r--src/mbgl/util/tile_cover.hpp5
103 files changed, 1604 insertions, 889 deletions
diff --git a/src/mbgl/algorithm/generate_clip_ids_impl.hpp b/src/mbgl/algorithm/generate_clip_ids_impl.hpp
index db62214220..6a316dcdad 100644
--- a/src/mbgl/algorithm/generate_clip_ids_impl.hpp
+++ b/src/mbgl/algorithm/generate_clip_ids_impl.hpp
@@ -17,7 +17,7 @@ void ClipIDGenerator::update(std::vector<std::reference_wrapper<Renderable>> ren
const auto end = renderables.end();
for (auto it = renderables.begin(); it != end; it++) {
auto& renderable = it->get();
- if (!renderable.used) {
+ if (!renderable.used || !renderable.needsClipping) {
continue;
}
diff --git a/src/mbgl/algorithm/update_renderables.hpp b/src/mbgl/algorithm/update_renderables.hpp
index 0c2266ff47..c583b6b2b6 100644
--- a/src/mbgl/algorithm/update_renderables.hpp
+++ b/src/mbgl/algorithm/update_renderables.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/tile/tile_necessity.hpp>
#include <mbgl/util/range.hpp>
-#include <mbgl/storage/resource.hpp>
#include <unordered_set>
@@ -40,15 +40,15 @@ void updateRenderables(GetTileFn getTile,
// if (source has the tile and bucket is loaded) {
if (tile->isRenderable()) {
- retainTile(*tile, Resource::Necessity::Required);
+ retainTile(*tile, TileNecessity::Required);
renderTile(idealRenderTileID, *tile);
} else {
// We are now attempting to load child and parent tiles.
- bool parentHasTriedOptional = tile->hasTriedOptional();
+ bool parentHasTriedOptional = tile->hasTriedCache();
bool parentIsLoaded = tile->isLoaded();
// The tile isn't loaded yet, but retain it anyway because it's an ideal tile.
- retainTile(*tile, Resource::Necessity::Required);
+ retainTile(*tile, TileNecessity::Required);
covered = true;
overscaledZ = dataTileZoom + 1;
if (overscaledZ > zoomRange.max) {
@@ -56,7 +56,7 @@ void updateRenderables(GetTileFn getTile,
const auto childDataTileID = idealDataTileID.scaledTo(overscaledZ);
tile = getTile(childDataTileID);
if (tile && tile->isRenderable()) {
- retainTile(*tile, Resource::Necessity::Optional);
+ retainTile(*tile, TileNecessity::Optional);
renderTile(idealRenderTileID, *tile);
} else {
covered = false;
@@ -67,7 +67,7 @@ void updateRenderables(GetTileFn getTile,
const OverscaledTileID childDataTileID(overscaledZ, idealRenderTileID.wrap, childTileID);
tile = getTile(childDataTileID);
if (tile && tile->isRenderable()) {
- retainTile(*tile, Resource::Necessity::Optional);
+ retainTile(*tile, TileNecessity::Optional);
renderTile(childDataTileID.toUnwrapped(), *tile);
} else {
// At least one child tile doesn't exist, so we are going to look for
@@ -97,12 +97,19 @@ void updateRenderables(GetTileFn getTile,
}
if (tile) {
- retainTile(*tile, parentIsLoaded ? Resource::Necessity::Required
- : Resource::Necessity::Optional);
+ if (!parentIsLoaded) {
+ // We haven't completed loading the child, so we only do an optional
+ // (cache) request in an attempt to quickly load data that we can show.
+ retainTile(*tile, TileNecessity::Optional);
+ } else {
+ // Now that we've checked the child and know for sure that we can't load
+ // it, we attempt to load the parent from the network.
+ retainTile(*tile, TileNecessity::Required);
+ }
// Save the current values, since they're the parent of the next iteration
// of the parent tile ascent loop.
- parentHasTriedOptional = tile->hasTriedOptional();
+ parentHasTriedOptional = tile->hasTriedCache();
parentIsLoaded = tile->isLoaded();
if (tile->isRenderable()) {
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index dbf8387ae0..1f2d01e9eb 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -39,19 +39,22 @@ AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation, cons
Annotation::visit(annotation, [&] (const auto& annotation_) {
this->add(id, annotation_, maxZoom);
});
+ dirty = true;
return id;
}
-Update AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
+bool AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
std::lock_guard<std::mutex> lock(mutex);
- return Annotation::visit(annotation, [&] (const auto& annotation_) {
- return this->update(id, annotation_, maxZoom);
+ Annotation::visit(annotation, [&] (const auto& annotation_) {
+ this->update(id, annotation_, maxZoom);
});
+ return dirty;
}
void AnnotationManager::removeAnnotation(const AnnotationID& id) {
std::lock_guard<std::mutex> lock(mutex);
remove(id);
+ dirty = true;
}
void AnnotationManager::add(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t) {
@@ -72,49 +75,45 @@ void AnnotationManager::add(const AnnotationID& id, const FillAnnotation& annota
impl.updateStyle(*style.get().impl);
}
-Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) {
- Update result = Update::Nothing;
-
+void AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) {
auto it = symbolAnnotations.find(id);
if (it == symbolAnnotations.end()) {
assert(false); // Attempt to update a non-existent symbol annotation
- return result;
+ return;
}
const SymbolAnnotation& existing = it->second->annotation;
if (existing.geometry != annotation.geometry || existing.icon != annotation.icon) {
- result |= Update::AnnotationData;
+ dirty = true;
remove(id);
add(id, annotation, maxZoom);
}
-
- return result;
}
-Update AnnotationManager::update(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) {
+void AnnotationManager::update(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) {
auto it = shapeAnnotations.find(id);
if (it == shapeAnnotations.end()) {
assert(false); // Attempt to update a non-existent shape annotation
- return Update::Nothing;
+ return;
}
shapeAnnotations.erase(it);
add(id, annotation, maxZoom);
- return Update::AnnotationData;
+ dirty = true;
}
-Update AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) {
+void AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) {
auto it = shapeAnnotations.find(id);
if (it == shapeAnnotations.end()) {
assert(false); // Attempt to update a non-existent shape annotation
- return Update::Nothing;
+ return;
}
shapeAnnotations.erase(it);
add(id, annotation, maxZoom);
- return Update::AnnotationData;
+ dirty = true;
}
void AnnotationManager::remove(const AnnotationID& id) {
@@ -187,8 +186,11 @@ void AnnotationManager::updateStyle() {
void AnnotationManager::updateData() {
std::lock_guard<std::mutex> lock(mutex);
- for (auto& tile : tiles) {
- tile->setData(getTileData(tile->id.canonical));
+ if (dirty) {
+ for (auto& tile : tiles) {
+ tile->setData(getTileData(tile->id.canonical));
+ }
+ dirty = false;
}
}
diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp
index dee823bc0f..a028a8f1ba 100644
--- a/src/mbgl/annotation/annotation_manager.hpp
+++ b/src/mbgl/annotation/annotation_manager.hpp
@@ -3,7 +3,6 @@
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/annotation/symbol_annotation_impl.hpp>
#include <mbgl/style/image.hpp>
-#include <mbgl/map/update.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mutex>
@@ -30,7 +29,7 @@ public:
~AnnotationManager();
AnnotationID addAnnotation(const Annotation&, const uint8_t maxZoom);
- Update updateAnnotation(const AnnotationID&, const Annotation&, const uint8_t maxZoom);
+ bool updateAnnotation(const AnnotationID&, const Annotation&, const uint8_t maxZoom);
void removeAnnotation(const AnnotationID&);
void addImage(std::unique_ptr<style::Image>);
@@ -53,9 +52,9 @@ private:
void add(const AnnotationID&, const LineAnnotation&, const uint8_t);
void add(const AnnotationID&, const FillAnnotation&, const uint8_t);
- Update update(const AnnotationID&, const SymbolAnnotation&, const uint8_t);
- Update update(const AnnotationID&, const LineAnnotation&, const uint8_t);
- Update update(const AnnotationID&, const FillAnnotation&, const uint8_t);
+ void update(const AnnotationID&, const SymbolAnnotation&, const uint8_t);
+ void update(const AnnotationID&, const LineAnnotation&, const uint8_t);
+ void update(const AnnotationID&, const FillAnnotation&, const uint8_t);
void remove(const AnnotationID&);
@@ -67,6 +66,8 @@ private:
std::mutex mutex;
+ bool dirty = false;
+
AnnotationID nextID = 0;
using SymbolAnnotationTree = boost::geometry::index::rtree<std::shared_ptr<const SymbolAnnotationImpl>, boost::geometry::index::rstar<16, 4>>;
diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp
index 0596d60f4f..d405418a45 100644
--- a/src/mbgl/annotation/annotation_tile.cpp
+++ b/src/mbgl/annotation/annotation_tile.cpp
@@ -19,9 +19,6 @@ AnnotationTile::~AnnotationTile() {
annotationManager.removeTile(*this);
}
-void AnnotationTile::setNecessity(Necessity) {
-}
-
class AnnotationTileFeatureData {
public:
AnnotationTileFeatureData(const AnnotationID id_,
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
index 88505c50e3..a4d1e66802 100644
--- a/src/mbgl/annotation/annotation_tile.hpp
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -14,8 +14,6 @@ public:
AnnotationTile(const OverscaledTileID&, const TileParameters&);
~AnnotationTile() override;
- void setNecessity(Necessity) final;
-
private:
AnnotationManager& annotationManager;
};
diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp
index c2e6191d1d..34fb576727 100644
--- a/src/mbgl/annotation/render_annotation_source.cpp
+++ b/src/mbgl/annotation/render_annotation_source.cpp
@@ -60,9 +60,9 @@ std::vector<std::reference_wrapper<RenderTile>> RenderAnnotationSource::getRende
std::unordered_map<std::string, std::vector<Feature>>
RenderAnnotationSource::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options);
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options);
}
std::vector<Feature> RenderAnnotationSource::querySourceFeatures(const SourceQueryOptions&) const {
diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp
index 4000c4b04a..6209c943f1 100644
--- a/src/mbgl/annotation/render_annotation_source.hpp
+++ b/src/mbgl/annotation/render_annotation_source.hpp
@@ -26,7 +26,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
@@ -43,7 +43,7 @@ private:
template <>
inline bool RenderSource::is<RenderAnnotationSource>() const {
- return baseImpl->type == SourceType::Annotations;
+ return baseImpl->type == style::SourceType::Annotations;
}
} // namespace mbgl
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp
index 4c4e985369..1adb933e44 100644
--- a/src/mbgl/geometry/feature_index.cpp
+++ b/src/mbgl/geometry/feature_index.cpp
@@ -1,5 +1,4 @@
#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/renderer/render_style.hpp>
#include <mbgl/renderer/render_layer.hpp>
#include <mbgl/renderer/query.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
@@ -9,7 +8,7 @@
#include <mbgl/math/minmax.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/tile_id.hpp>
#include <mapbox/geometry/envelope.hpp>
@@ -32,19 +31,6 @@ void FeatureIndex::insert(const GeometryCollection& geometries,
}
}
-static bool vectorContains(const std::vector<std::string>& vector, const std::string& s) {
- return std::find(vector.begin(), vector.end(), s) != vector.end();
-}
-
-static bool vectorsIntersect(const std::vector<std::string>& vectorA, const std::vector<std::string>& vectorB) {
- for (const auto& a : vectorA) {
- if (vectorContains(vectorB, a)) {
- return true;
- }
- }
- return false;
-}
-
static bool topDown(const IndexedSubfeature& a, const IndexedSubfeature& b) {
return a.sortIndex > b.sortIndex;
}
@@ -53,36 +39,6 @@ static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature&
return a.sortIndex < b.sortIndex;
}
-static int16_t getAdditionalQueryRadius(const RenderedQueryOptions& queryOptions,
- const RenderStyle& style,
- const GeometryTile& tile,
- const float pixelsToTileUnits) {
-
- // Determine the additional radius needed factoring in property functions
- float additionalRadius = 0;
- auto getQueryRadius = [&](const RenderLayer& layer) {
- auto bucket = tile.getBucket(*layer.baseImpl);
- if (bucket) {
- additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(layer) * pixelsToTileUnits);
- }
- };
-
- if (queryOptions.layerIDs) {
- for (const auto& layerID : *queryOptions.layerIDs) {
- const RenderLayer* layer = style.getRenderLayer(layerID);
- if (layer) {
- getQueryRadius(*layer);
- }
- }
- } else {
- for (const RenderLayer* layer : style.getRenderLayers()) {
- getQueryRadius(*layer);
- }
- }
-
- return std::min<int16_t>(util::EXTENT, additionalRadius);
-}
-
void FeatureIndex::query(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
@@ -92,13 +48,13 @@ void FeatureIndex::query(
const RenderedQueryOptions& queryOptions,
const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const CollisionTile* collisionTile,
- const GeometryTile& tile) const {
+ const float additionalQueryRadius) const {
// Determine query radius
const float pixelsToTileUnits = util::EXTENT / tileSize / scale;
- const int16_t additionalRadius = getAdditionalQueryRadius(queryOptions, style, tile, pixelsToTileUnits);
+ const int16_t additionalRadius = std::min<int16_t>(util::EXTENT, additionalQueryRadius * pixelsToTileUnits);
// Query the grid index
mapbox::geometry::box<int16_t> box = mapbox::geometry::envelope(queryGeometry);
@@ -113,7 +69,7 @@ void FeatureIndex::query(
if (indexedFeature.sortIndex == previousSortIndex) continue;
previousSortIndex = indexedFeature.sortIndex;
- addFeature(result, indexedFeature, queryGeometry, queryOptions, geometryTileData, tileID, style, bearing, pixelsToTileUnits);
+ addFeature(result, indexedFeature, queryGeometry, queryOptions, geometryTileData, tileID, layers, bearing, pixelsToTileUnits);
}
// Query symbol features, if they've been placed.
@@ -124,7 +80,7 @@ void FeatureIndex::query(
std::vector<IndexedSubfeature> symbolFeatures = collisionTile->queryRenderedSymbols(queryGeometry, scale);
std::sort(symbolFeatures.begin(), symbolFeatures.end(), topDownSymbols);
for (const auto& symbolFeature : symbolFeatures) {
- addFeature(result, symbolFeature, queryGeometry, queryOptions, geometryTileData, tileID, style, bearing, pixelsToTileUnits);
+ addFeature(result, symbolFeature, queryGeometry, queryOptions, geometryTileData, tileID, layers, bearing, pixelsToTileUnits);
}
}
@@ -135,30 +91,39 @@ void FeatureIndex::addFeature(
const RenderedQueryOptions& options,
const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const float bearing,
const float pixelsToTileUnits) const {
- auto& layerIDs = bucketLayerIDs.at(indexedFeature.bucketName);
- if (options.layerIDs && !vectorsIntersect(layerIDs, *options.layerIDs)) {
- return;
- }
-
- auto sourceLayer = geometryTileData.getLayer(indexedFeature.sourceLayerName);
- assert(sourceLayer);
+ auto getRenderLayer = [&] (const std::string& layerID) -> const RenderLayer* {
+ for (const auto& layer : layers) {
+ if (layer->getID() == layerID) {
+ return layer;
+ }
+ }
+ return nullptr;
+ };
- auto geometryTileFeature = sourceLayer->getFeature(indexedFeature.index);
- assert(geometryTileFeature);
+ // Lazily calculated.
+ std::unique_ptr<GeometryTileLayer> sourceLayer;
+ std::unique_ptr<GeometryTileFeature> geometryTileFeature;
- for (const auto& layerID : layerIDs) {
- if (options.layerIDs && !vectorContains(*options.layerIDs, layerID)) {
+ for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketName)) {
+ const RenderLayer* renderLayer = getRenderLayer(layerID);
+ if (!renderLayer) {
continue;
}
- auto renderLayer = style.getRenderLayer(layerID);
- if (!renderLayer ||
- (!renderLayer->is<RenderSymbolLayer>() &&
- !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, bearing, pixelsToTileUnits))) {
+ if (!geometryTileFeature) {
+ sourceLayer = geometryTileData.getLayer(indexedFeature.sourceLayerName);
+ assert(sourceLayer);
+
+ geometryTileFeature = sourceLayer->getFeature(indexedFeature.index);
+ assert(geometryTileFeature);
+ }
+
+ if (!renderLayer->is<RenderSymbolLayer>() &&
+ !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, bearing, pixelsToTileUnits)) {
continue;
}
diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp
index 83f339a9de..2ae7da33df 100644
--- a/src/mbgl/geometry/feature_index.hpp
+++ b/src/mbgl/geometry/feature_index.hpp
@@ -11,9 +11,8 @@
namespace mbgl {
-class GeometryTile;
class RenderedQueryOptions;
-class RenderStyle;
+class RenderLayer;
class CollisionTile;
class CanonicalTileID;
@@ -42,9 +41,9 @@ public:
const RenderedQueryOptions& options,
const GeometryTileData&,
const CanonicalTileID&,
- const RenderStyle&,
+ const std::vector<const RenderLayer*>&,
const CollisionTile*,
- const GeometryTile& tile) const;
+ const float additionalQueryRadius) const;
static optional<GeometryCoordinates> translateQueryGeometry(
const GeometryCoordinates& queryGeometry,
@@ -63,7 +62,7 @@ private:
const RenderedQueryOptions& options,
const GeometryTileData&,
const CanonicalTileID&,
- const RenderStyle&,
+ const std::vector<const RenderLayer*>&,
const float bearing,
const float pixelsToTileUnits) const;
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index e18f1e0bcf..d0c538efb0 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -87,7 +87,9 @@ static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mis
Context::Context() = default;
Context::~Context() {
- reset();
+ if (cleanupOnDestruction) {
+ reset();
+ }
}
void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) {
@@ -457,6 +459,9 @@ Framebuffer Context::createFramebuffer(const Texture& color) {
Framebuffer
Context::createFramebuffer(const Texture& color,
const Renderbuffer<RenderbufferType::DepthComponent>& depthTarget) {
+ if (color.size != depthTarget.size) {
+ throw std::runtime_error("Renderbuffer size mismatch");
+ }
auto fbo = createFramebuffer();
bindFramebuffer = fbo;
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color.texture, 0));
@@ -481,7 +486,7 @@ Context::createTexture(const Size size, const void* data, TextureFormat format,
void Context::updateTexture(
TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit) {
- activeTexture = unit;
+ activeTextureUnit = unit;
texture[unit] = id;
MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLenum>(format), size.width,
size.height, 0, static_cast<GLenum>(format), GL_UNSIGNED_BYTE,
@@ -495,7 +500,7 @@ void Context::bindTexture(Texture& obj,
TextureWrap wrapX,
TextureWrap wrapY) {
if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) {
- activeTexture = unit;
+ activeTextureUnit = unit;
texture[unit] = obj.texture;
if (filter != obj.filter || mipmap != obj.mipmap) {
@@ -526,7 +531,7 @@ void Context::bindTexture(Texture& obj,
} else if (texture[unit] != obj.texture) {
// We are checking first to avoid setting the active texture without a subsequent
// texture bind.
- activeTexture = unit;
+ activeTextureUnit = unit;
texture[unit] = obj.texture;
}
}
@@ -558,7 +563,7 @@ void Context::setDirtyState() {
clearStencil.setDirty();
program.setDirty();
lineWidth.setDirty();
- activeTexture.setDirty();
+ activeTextureUnit.setDirty();
pixelStorePack.setDirty();
pixelStoreUnpack.setDirty();
#if not MBGL_USE_GLES2
@@ -709,8 +714,10 @@ void Context::performCleanup() {
if (!abandonedTextures.empty()) {
for (const auto id : abandonedTextures) {
- if (activeTexture == id) {
- activeTexture.setDirty();
+ for (auto& binding : texture) {
+ if (binding == id) {
+ binding.setDirty();
+ }
}
}
MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data()));
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 9923567276..528113cbba 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -190,7 +190,13 @@ public:
return vertexArray.get();
}
+ void setCleanupOnDestruction(bool cleanup) {
+ cleanupOnDestruction = cleanup;
+ }
+
private:
+ bool cleanupOnDestruction = true;
+
std::unique_ptr<extension::Debugging> debugging;
std::unique_ptr<extension::VertexArray> vertexArray;
#if MBGL_HAS_BINARY_PROGRAMS
@@ -198,7 +204,7 @@ private:
#endif
public:
- State<value::ActiveTexture> activeTexture;
+ State<value::ActiveTextureUnit> activeTextureUnit;
State<value::BindFramebuffer> bindFramebuffer;
State<value::Viewport> viewport;
State<value::ScissorTest> scissorTest;
diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp
index cc8ff13268..0592557a7f 100644
--- a/src/mbgl/gl/renderbuffer.hpp
+++ b/src/mbgl/gl/renderbuffer.hpp
@@ -9,9 +9,23 @@ namespace gl {
template <RenderbufferType renderbufferType>
class Renderbuffer {
public:
+ Renderbuffer(Size size_, UniqueRenderbuffer renderbuffer_, bool dirty_ = false)
+ : size(std::move(size_)), renderbuffer(std::move(renderbuffer_)), dirty(dirty_) {
+ }
+
using type = std::integral_constant<RenderbufferType, renderbufferType>;
Size size;
- gl::UniqueRenderbuffer renderbuffer;
+ UniqueRenderbuffer renderbuffer;
+
+ void shouldClear(bool clear) {
+ dirty = clear;
+ }
+ bool needsClearing() {
+ return dirty;
+ }
+
+private:
+ bool dirty;
};
} // namespace gl
diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp
index 89014fe6bc..092403af0d 100644
--- a/src/mbgl/gl/value.cpp
+++ b/src/mbgl/gl/value.cpp
@@ -242,13 +242,13 @@ LineWidth::Type LineWidth::Get() {
return lineWidth;
}
-const constexpr ActiveTexture::Type ActiveTexture::Default;
+const constexpr ActiveTextureUnit::Type ActiveTextureUnit::Default;
-void ActiveTexture::Set(const Type& value) {
+void ActiveTextureUnit::Set(const Type& value) {
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0 + value));
}
-ActiveTexture::Type ActiveTexture::Get() {
+ActiveTextureUnit::Type ActiveTextureUnit::Get() {
GLint activeTexture;
MBGL_CHECK_ERROR(glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture));
return static_cast<Type>(activeTexture - GL_TEXTURE0);
diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp
index 19e9af194f..7b85a5ff4b 100644
--- a/src/mbgl/gl/value.hpp
+++ b/src/mbgl/gl/value.hpp
@@ -165,7 +165,7 @@ struct LineWidth {
static Type Get();
};
-struct ActiveTexture {
+struct ActiveTextureUnit {
using Type = TextureUnit;
static const constexpr Type Default = 0;
static void Set(const Type&);
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 229b8f2ee2..2c90b69b08 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -205,11 +205,11 @@ void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyph
const Shaping result = getShaping(
/* string */ text,
/* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
- layout.get<TextMaxWidth>() * oneEm : 0,
+ layout.evaluate<TextMaxWidth>(zoom, feature) * oneEm : 0,
/* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm,
/* anchor */ layout.evaluate<TextAnchor>(zoom, feature),
/* justify */ layout.evaluate<TextJustify>(zoom, feature),
- /* spacing: ems */ util::i18n::allowsLetterSpacing(*feature.text) ? layout.get<TextLetterSpacing>() * oneEm : 0.0f,
+ /* spacing: ems */ util::i18n::allowsLetterSpacing(*feature.text) ? layout.evaluate<TextLetterSpacing>(zoom, feature) * oneEm : 0.0f,
/* translate */ Point<float>(layout.evaluate<TextOffset>(zoom, feature)[0] * oneEm, layout.evaluate<TextOffset>(zoom, feature)[1] * oneEm),
/* verticalHeight */ oneEm,
/* writingMode */ writingMode,
@@ -233,6 +233,7 @@ void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyph
shapedIcon = PositionedIcon::shapeIcon(
imagePositions.at(*feature.icon),
layout.evaluate<IconOffset>(zoom, feature),
+ layout.evaluate<IconAnchor>(zoom, feature),
layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
if (image->second->sdf) {
sdfIcons = true;
diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp
index 8ccd6a0410..279d251f8f 100644
--- a/src/mbgl/layout/symbol_projection.cpp
+++ b/src/mbgl/layout/symbol_projection.cpp
@@ -94,10 +94,12 @@ namespace mbgl {
}
- Point<float> project(const Point<float>& point, const mat4& matrix) {
+ typedef std::pair<Point<float>,float> PointAndCameraDistance;
+
+ PointAndCameraDistance project(const Point<float>& point, const mat4& matrix) {
vec4 pos = {{ point.x, point.y, 0, 1 }};
matrix::transformMat4(pos, pos, matrix);
- return { static_cast<float>(pos[0] / pos[3]), static_cast<float>(pos[1] / pos[3]) };
+ return {{ static_cast<float>(pos[0] / pos[3]), static_cast<float>(pos[1] / pos[3]) }, pos[3] };
}
float evaluateSizeForFeature(const ZoomEvaluatedSize& zoomEvaluatedSize, const PlacedSymbol& placedSymbol) {
@@ -150,9 +152,20 @@ namespace mbgl {
NotEnoughRoom,
NeedsFlipping
};
+
+ Point<float> projectTruncatedLineSegment(const Point<float>& previousTilePoint, const Point<float>& currentTilePoint, const Point<float>& previousProjectedPoint, const float minimumLength, const mat4& projectionMatrix) {
+ // We are assuming "previousTilePoint" won't project to a point within one unit of the camera plane
+ // If it did, that would mean our label extended all the way out from within the viewport to a (very distant)
+ // point near the plane of the camera. We wouldn't be able to render the label anyway once it crossed the
+ // plane of the camera.
+ const Point<float> projectedUnitVertex = project(previousTilePoint + util::unit<float>(previousTilePoint - currentTilePoint), projectionMatrix).first;
+ const Point<float> projectedUnitSegment = previousProjectedPoint - projectedUnitVertex;
+
+ return previousProjectedPoint + (projectedUnitSegment * (minimumLength / util::mag<float>(projectedUnitSegment)));
+ }
optional<PlacedGlyph> placeGlyphAlongLine(const float offsetX, const float lineOffsetX, const float lineOffsetY, const bool flip,
- Point<float> anchorPoint, const uint16_t anchorSegment, const GeometryCoordinates& line, const mat4& labelPlaneMatrix) {
+ const Point<float>& projectedAnchorPoint, const Point<float>& tileAnchorPoint, const uint16_t anchorSegment, const GeometryCoordinates& line, const mat4& labelPlaneMatrix) {
const float combinedOffsetX = flip ?
offsetX - lineOffsetX :
@@ -172,8 +185,8 @@ namespace mbgl {
int32_t currentIndex = dir > 0 ? anchorSegment : anchorSegment + 1;
- Point<float> current = anchorPoint;
- Point<float> prev = anchorPoint;
+ Point<float> current = projectedAnchorPoint;
+ Point<float> prev = projectedAnchorPoint;
float distanceToPrev = 0.0;
float currentSegmentDistance = 0.0;
const float absOffsetX = std::abs(combinedOffsetX);
@@ -185,7 +198,18 @@ namespace mbgl {
if (currentIndex < 0 || currentIndex >= static_cast<int32_t>(line.size())) return {};
prev = current;
- current = project(convertPoint<float>(line.at(currentIndex)), labelPlaneMatrix);
+ PointAndCameraDistance projection = project(convertPoint<float>(line.at(currentIndex)), labelPlaneMatrix);
+ if (projection.second > 0) {
+ current = projection.first;
+ } else {
+ // The vertex is behind the plane of the camera, so we can't project it
+ // Instead, we'll create a vertex along the line that's far enough to include the glyph
+ const Point<float> previousTilePoint = distanceToPrev == 0 ?
+ tileAnchorPoint :
+ convertPoint<float>(line.at(currentIndex - dir));
+ const Point<float> currentTilePoint = convertPoint<float>(line.at(currentIndex));
+ current = projectTruncatedLineSegment(previousTilePoint, currentTilePoint, prev, absOffsetX - distanceToPrev + 1, labelPlaneMatrix);
+ }
distanceToPrev += currentSegmentDistance;
currentSegmentDistance = util::dist<float>(prev, current);
@@ -211,29 +235,28 @@ namespace mbgl {
const mat4& posMatrix,
const mat4& labelPlaneMatrix,
const mat4& glCoordMatrix,
- gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex>& dynamicVertexArray) {
+ gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex>& dynamicVertexArray,
+ const Point<float>& projectedAnchorPoint) {
const float fontScale = fontSize / 24.0;
const float lineOffsetX = symbol.lineOffset[0] * fontSize;
const float lineOffsetY = symbol.lineOffset[1] * fontSize;
- const Point<float> anchorPoint = project(symbol.anchorPoint, labelPlaneMatrix);
-
std::vector<PlacedGlyph> placedGlyphs;
if (symbol.glyphOffsets.size() > 1) {
const float firstGlyphOffset = symbol.glyphOffsets.front();
const float lastGlyphOffset = symbol.glyphOffsets.back();
- optional<PlacedGlyph> firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
+ optional<PlacedGlyph> firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, projectedAnchorPoint, symbol.anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
if (!firstPlacedGlyph)
return PlacementResult::NotEnoughRoom;
- optional<PlacedGlyph> lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
+ optional<PlacedGlyph> lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, projectedAnchorPoint, symbol.anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
if (!lastPlacedGlyph)
return PlacementResult::NotEnoughRoom;
- const Point<float> firstPoint = project(firstPlacedGlyph->point, glCoordMatrix);
- const Point<float> lastPoint = project(lastPlacedGlyph->point, glCoordMatrix);
+ const Point<float> firstPoint = project(firstPlacedGlyph->point, glCoordMatrix).first;
+ const Point<float> lastPoint = project(lastPlacedGlyph->point, glCoordMatrix).first;
if (keepUpright && !flip &&
(symbol.useVerticalMode ? firstPoint.y < lastPoint.y : firstPoint.x > lastPoint.x)) {
@@ -244,7 +267,7 @@ namespace mbgl {
for (size_t glyphIndex = 1; glyphIndex < symbol.glyphOffsets.size() - 1; glyphIndex++) {
const float glyphOffsetX = symbol.glyphOffsets[glyphIndex];
// Since first and last glyph fit on the line, we're sure that the rest of the glyphs can be placed
- auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
+ auto placedGlyph = placeGlyphAlongLine(glyphOffsetX * fontScale, lineOffsetX, lineOffsetY, flip, projectedAnchorPoint, symbol.anchorPoint, symbol.segment, symbol.line, labelPlaneMatrix);
placedGlyphs.push_back(*placedGlyph);
}
placedGlyphs.push_back(*lastPlacedGlyph);
@@ -252,15 +275,23 @@ namespace mbgl {
// Only a single glyph to place
// So, determine whether to flip based on projected angle of the line segment it's on
if (keepUpright && !flip) {
- const Point<float> a = project(convertPoint<float>(symbol.line.at(symbol.segment)), posMatrix);
- const Point<float> b = project(convertPoint<float>(symbol.line.at(symbol.segment + 1)), posMatrix);
+ const Point<float> a = project(symbol.anchorPoint, posMatrix).first;
+ const Point<float> tileSegmentEnd = convertPoint<float>(symbol.line.at(symbol.segment + 1));
+ const PointAndCameraDistance projectedVertex = project(tileSegmentEnd, posMatrix);
+ // We know the anchor will be in the viewport, but the end of the line segment may be
+ // behind the plane of the camera, in which case we can use a point at any arbitrary (closer)
+ // point on the segment.
+ const Point<float> b = (projectedVertex.second > 0) ?
+ projectedVertex.first :
+ projectTruncatedLineSegment(symbol.anchorPoint,tileSegmentEnd, a, 1, posMatrix);
+
if (symbol.useVerticalMode ? b.y > a.y : b.x < a.x) {
return PlacementResult::NeedsFlipping;
}
}
assert(symbol.glyphOffsets.size() == 1); // We are relying on SymbolInstance.hasText filtering out symbols without any glyphs at all
const float glyphOffsetX = symbol.glyphOffsets.front();
- optional<PlacedGlyph> singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment,
+ optional<PlacedGlyph> singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetX, lineOffsetX, lineOffsetY, flip, projectedAnchorPoint, symbol.anchorPoint, symbol.segment,
symbol.line, labelPlaneMatrix);
if (!singleGlyph)
return PlacementResult::NotEnoughRoom;
@@ -275,6 +306,7 @@ namespace mbgl {
return PlacementResult::OK;
}
+
void reprojectLineLabels(gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex>& dynamicVertexArray, const std::vector<PlacedSymbol>& placedSymbols,
const mat4& posMatrix, const style::SymbolPropertyValues& values,
const RenderTile& tile, const SymbolSizeBinder& sizeBinder, const TransformState& state, const FrameHistory& frameHistory) {
@@ -311,12 +343,14 @@ namespace mbgl {
const float pitchScaledFontSize = values.pitchAlignment == style::AlignmentType::Map ?
fontSize * perspectiveRatio :
fontSize / perspectiveRatio;
+
+ const Point<float> anchorPoint = project(placedSymbol.anchorPoint, labelPlaneMatrix).first;
- PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray);
+ PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint);
if (placeUnflipped == PlacementResult::NotEnoughRoom ||
(placeUnflipped == PlacementResult::NeedsFlipping &&
- placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray) == PlacementResult::NotEnoughRoom)) {
+ placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint) == PlacementResult::NotEnoughRoom)) {
hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray);
}
}
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index d5a5923e6c..378bd40ab7 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -50,7 +50,7 @@ public:
// StyleObserver
void onSourceChanged(style::Source&) override;
- void onUpdate(Update) override;
+ void onUpdate() override;
void onStyleLoading() override;
void onStyleLoaded() override;
void onStyleError(std::exception_ptr) override;
@@ -166,11 +166,18 @@ void Map::renderStill(StillImageCallback callback) {
impl->stillImageRequest = std::make_unique<StillImageRequest>(std::move(callback));
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
+}
+
+void Map::renderStill(const CameraOptions& camera, MapDebugOptions debugOptions, StillImageCallback callback) {
+ impl->cameraMutated = true;
+ impl->debugOptions = debugOptions;
+ impl->transform.jumpTo(camera);
+ renderStill(std::move(callback));
}
void Map::triggerRepaint() {
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
#pragma mark - Map::Impl RendererObserver
@@ -194,8 +201,11 @@ void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepai
observer.onDidFinishRenderingFrame(MapObserver::RenderMode(renderMode));
if (needsRepaint || transform.inTransition()) {
- onUpdate(Update::Repaint);
+ onUpdate();
}
+ } else if (stillImageRequest && rendererFullyLoaded) {
+ auto request = std::move(stillImageRequest);
+ request->callback(nullptr);
}
}
@@ -206,9 +216,6 @@ void Map::Impl::onDidFinishRenderingMap() {
loading = false;
observer.onDidFinishLoadingMap();
}
- } else if (stillImageRequest) {
- auto request = std::move(stillImageRequest);
- request->callback(nullptr);
}
};
@@ -233,12 +240,12 @@ void Map::setStyle(std::unique_ptr<Style> style) {
void Map::cancelTransitions() {
impl->transform.cancelTransitions();
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::setGestureInProgress(bool inProgress) {
impl->transform.setGestureInProgress(inProgress);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
bool Map::isGestureInProgress() const {
@@ -266,19 +273,19 @@ CameraOptions Map::getCameraOptions(const EdgeInsets& padding) const {
void Map::jumpTo(const CameraOptions& camera) {
impl->cameraMutated = true;
impl->transform.jumpTo(camera);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.easeTo(camera, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.flyTo(camera, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
#pragma mark - Position
@@ -286,7 +293,7 @@ void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation)
void Map::moveBy(const ScreenCoordinate& point, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.moveBy(point, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::setLatLng(const LatLng& latLng, const AnimationOptions& animation) {
@@ -297,13 +304,13 @@ void Map::setLatLng(const LatLng& latLng, const AnimationOptions& animation) {
void Map::setLatLng(const LatLng& latLng, const EdgeInsets& padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setLatLng(latLng, padding, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setLatLng(latLng, anchor, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
LatLng Map::getLatLng(const EdgeInsets& padding) const {
@@ -319,7 +326,7 @@ void Map::resetPosition(const EdgeInsets& padding) {
camera.padding = padding;
camera.zoom = 0;
impl->transform.jumpTo(camera);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
@@ -333,13 +340,13 @@ void Map::setZoom(double zoom, const AnimationOptions& animation) {
void Map::setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setZoom(zoom, anchor, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::setZoom(double zoom, const EdgeInsets& padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setZoom(zoom, padding, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
double Map::getZoom() const {
@@ -354,30 +361,30 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const AnimationOption
void Map::setLatLngZoom(const LatLng& latLng, double zoom, const EdgeInsets& padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setLatLngZoom(latLng, zoom, padding, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
-CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding) const {
+CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding, optional<double> bearing) const {
return cameraForLatLngs({
bounds.northwest(),
bounds.southwest(),
bounds.southeast(),
bounds.northeast(),
- }, padding);
+ }, padding, bearing);
}
-CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const EdgeInsets& padding) const {
+CameraOptions cameraForLatLngs(const std::vector<LatLng>& latLngs, const Transform& transform, const EdgeInsets& padding) {
CameraOptions options;
if (latLngs.empty()) {
return options;
}
-
+ Size size = transform.getState().getSize();
// Calculate the bounds of the possibly rotated shape with respect to the viewport.
ScreenCoordinate nePixel = {-INFINITY, -INFINITY};
ScreenCoordinate swPixel = {INFINITY, INFINITY};
- double viewportHeight = getSize().height;
+ double viewportHeight = size.height;
for (LatLng latLng : latLngs) {
- ScreenCoordinate pixel = impl->transform.latLngToScreenCoordinate(latLng);
+ ScreenCoordinate pixel = transform.latLngToScreenCoordinate(latLng);
swPixel.x = std::min(swPixel.x, pixel.x);
nePixel.x = std::max(nePixel.x, pixel.x);
swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y);
@@ -389,14 +396,14 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const Ed
// Calculate the zoom level.
double minScale = INFINITY;
if (width > 0 || height > 0) {
- double scaleX = double(getSize().width) / width;
- double scaleY = double(getSize().height) / height;
+ double scaleX = double(size.width) / width;
+ double scaleY = double(size.height) / height;
scaleX -= (padding.left() + padding.right()) / width;
scaleY -= (padding.top() + padding.bottom()) / height;
minScale = util::min(scaleX, scaleY);
}
- double zoom = getZoom() + util::log2(minScale);
- zoom = util::clamp(zoom, getMinZoom(), getMaxZoom());
+ double zoom = transform.getZoom() + util::log2(minScale);
+ zoom = util::clamp(zoom, transform.getState().getMinZoom(), transform.getState().getMaxZoom());
// Calculate the center point of a virtual bounds that is extended in all directions by padding.
ScreenCoordinate centerPixel = nePixel + swPixel;
@@ -414,11 +421,34 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const Ed
// CameraOptions origin is at the top-left corner.
centerPixel.y = viewportHeight - centerPixel.y;
- options.center = latLngForPixel(centerPixel);
+ options.center = transform.screenCoordinateToLatLng(centerPixel);
options.zoom = zoom;
return options;
}
+CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const EdgeInsets& padding, optional<double> bearing) const {
+ if(bearing) {
+ double angle = -*bearing * util::DEG2RAD; // Convert to radians
+ Transform transform(impl->transform.getState());
+ transform.setAngle(angle);
+ CameraOptions options = mbgl::cameraForLatLngs(latLngs, transform, padding);
+ options.angle = angle;
+ return options;
+ } else {
+ return mbgl::cameraForLatLngs(latLngs, impl->transform, padding);
+ }
+}
+
+CameraOptions Map::cameraForGeometry(const Geometry<double>& geometry, const EdgeInsets& padding, optional<double> bearing) const {
+
+ std::vector<LatLng> latLngs;
+ forEachPoint(geometry, [&](const Point<double>& pt) {
+ latLngs.push_back({ pt.y, pt.x });
+ });
+ return cameraForLatLngs(latLngs, padding, bearing);
+
+}
+
LatLngBounds Map::latLngBoundsForCamera(const CameraOptions& camera) const {
Transform shallow { impl->transform.getState() };
Size size = shallow.getState().getSize();
@@ -444,7 +474,7 @@ optional<LatLngBounds> Map::getLatLngBounds() const {
void Map::setLatLngBounds(optional<LatLngBounds> bounds) {
impl->cameraMutated = true;
impl->transform.setLatLngBounds(bounds);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::setMinZoom(const double minZoom) {
@@ -495,7 +525,7 @@ double Map::getMaxPitch() const {
void Map::setSize(const Size size) {
impl->transform.resize(size);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
Size Map::getSize() const {
@@ -507,7 +537,7 @@ Size Map::getSize() const {
void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.rotateBy(first, second, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::setBearing(double degrees, const AnimationOptions& animation) {
@@ -518,13 +548,13 @@ void Map::setBearing(double degrees, const AnimationOptions& animation) {
void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::setBearing(double degrees, const EdgeInsets& padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setAngle(-degrees * util::DEG2RAD, padding, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
double Map::getBearing() const {
@@ -534,7 +564,7 @@ double Map::getBearing() const {
void Map::resetNorth(const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setAngle(0, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
#pragma mark - Pitch
@@ -547,7 +577,7 @@ void Map::setPitch(double pitch, const AnimationOptions& animation) {
void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
impl->transform.setPitch(pitch * util::DEG2RAD, anchor, animation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
double Map::getPitch() const {
@@ -558,7 +588,7 @@ double Map::getPitch() const {
void Map::setNorthOrientation(NorthOrientation orientation) {
impl->transform.setNorthOrientation(orientation);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
NorthOrientation Map::getNorthOrientation() const {
@@ -569,7 +599,7 @@ NorthOrientation Map::getNorthOrientation() const {
void Map::setConstrainMode(mbgl::ConstrainMode mode) {
impl->transform.setConstrainMode(mode);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
ConstrainMode Map::getConstrainMode() const {
@@ -580,13 +610,42 @@ ConstrainMode Map::getConstrainMode() const {
void Map::setViewportMode(mbgl::ViewportMode mode) {
impl->transform.setViewportMode(mode);
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
ViewportMode Map::getViewportMode() const {
return impl->transform.getViewportMode();
}
+#pragma mark - Projection mode
+
+void Map::setAxonometric(bool axonometric) {
+ impl->transform.setAxonometric(axonometric);
+ impl->onUpdate();
+}
+
+bool Map::getAxonometric() const {
+ return impl->transform.getAxonometric();
+}
+
+void Map::setXSkew(double xSkew) {
+ impl->transform.setXSkew(xSkew);
+ impl->onUpdate();
+}
+
+double Map::getXSkew() const {
+ return impl->transform.getXSkew();
+}
+
+void Map::setYSkew(double ySkew) {
+ impl->transform.setYSkew(ySkew);
+ impl->onUpdate();
+}
+
+double Map::getYSkew() const {
+ return impl->transform.getYSkew();
+}
+
#pragma mark - Projection
ScreenCoordinate Map::pixelForLatLng(const LatLng& latLng) const {
@@ -618,24 +677,26 @@ double Map::getTopOffsetPixelsForAnnotationImage(const std::string& id) {
AnnotationID Map::addAnnotation(const Annotation& annotation) {
auto result = impl->annotationManager.addAnnotation(annotation, getMaxZoom());
- impl->onUpdate(Update::AnnotationData);
+ impl->onUpdate();
return result;
}
void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) {
- impl->onUpdate(impl->annotationManager.updateAnnotation(id, annotation, getMaxZoom()));
+ if (impl->annotationManager.updateAnnotation(id, annotation, getMaxZoom())) {
+ impl->onUpdate();
+ }
}
void Map::removeAnnotation(AnnotationID annotation) {
impl->annotationManager.removeAnnotation(annotation);
- impl->onUpdate(Update::AnnotationData);
+ impl->onUpdate();
}
#pragma mark - Toggles
void Map::setDebug(MapDebugOptions debugOptions) {
impl->debugOptions = debugOptions;
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
void Map::cycleDebugOptions() {
@@ -659,7 +720,7 @@ void Map::cycleDebugOptions() {
else
impl->debugOptions = MapDebugOptions::TileBorders;
- impl->onUpdate(Update::Repaint);
+ impl->onUpdate();
}
MapDebugOptions Map::getDebug() const {
@@ -683,18 +744,14 @@ void Map::Impl::onSourceChanged(style::Source& source) {
}
void Map::Impl::onInvalidate() {
- onUpdate(Update::Repaint);
+ onUpdate();
}
-void Map::Impl::onUpdate(Update flags) {
+void Map::Impl::onUpdate() {
TimePoint timePoint = mode == MapMode::Continuous ? Clock::now() : Clock::time_point::max();
transform.updateTransitions(timePoint);
- if (flags & Update::AnnotationData) {
- annotationManager.updateData();
- }
-
UpdateParameters params = {
style->impl->isLoaded(),
mode,
@@ -709,8 +766,6 @@ void Map::Impl::onUpdate(Update flags) {
style->impl->getImageImpls(),
style->impl->getSourceImpls(),
style->impl->getLayerImpls(),
- scheduler,
- fileSource,
annotationManager,
prefetchZoomDelta,
bool(stillImageRequest)
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 2bb25af28f..105adf0400 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -527,6 +527,32 @@ ViewportMode Transform::getViewportMode() const {
return state.getViewportMode();
}
+#pragma mark - Projection mode
+
+void Transform::setAxonometric(bool axonometric) {
+ state.axonometric = axonometric;
+}
+
+bool Transform::getAxonometric() const {
+ return state.axonometric;
+}
+
+void Transform::setXSkew(double xSkew) {
+ state.xSkew = xSkew;
+}
+
+double Transform::getXSkew() const {
+ return state.xSkew;
+}
+
+void Transform::setYSkew(double ySkew) {
+ state.ySkew = ySkew;
+}
+
+double Transform::getYSkew() const {
+ return state.ySkew;
+}
+
#pragma mark - Transition
void Transform::startTransition(const CameraOptions& camera,
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index 749228bdf5..d429c57661 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -125,6 +125,14 @@ public:
void setViewportMode(ViewportMode);
ViewportMode getViewportMode() const;
+ // Projection mode
+ void setAxonometric(bool);
+ bool getAxonometric() const;
+ void setXSkew(double xSkew);
+ double getXSkew() const;
+ void setYSkew(double ySkew);
+ double getYSkew() const;
+
// Transitions
bool inTransition() const;
void updateTransitions(const TimePoint& now);
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index 4606e3eece..d79a65c61e 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -66,6 +66,15 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ) const {
matrix::translate(projMatrix, projMatrix, pixel_x() - size.width / 2.0f,
pixel_y() - size.height / 2.0f, 0);
+ if (axonometric) {
+ // mat[11] controls perspective
+ projMatrix[11] = 0;
+
+ // mat[8], mat[9] control x-skew, y-skew
+ projMatrix[8] = xSkew;
+ projMatrix[9] = ySkew;
+ }
+
matrix::scale(projMatrix, projMatrix, 1, 1,
1.0 / Projection::getMetersPerPixelAtLatitude(getLatLng(LatLng::Unwrapped).latitude(), getZoom()));
}
@@ -132,7 +141,7 @@ double TransformState::getZoom() const {
return scaleZoom(scale);
}
-int32_t TransformState::getIntegerZoom() const {
+uint8_t TransformState::getIntegerZoom() const {
return getZoom();
}
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index 4d6b89573e..0dd6d5a15e 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -47,7 +47,7 @@ public:
// Zoom
double getZoom() const;
- int32_t getIntegerZoom() const;
+ uint8_t getIntegerZoom() const;
double getZoomFraction() const;
// Bounds
@@ -134,6 +134,9 @@ private:
// `fov = 2 * arctan((height / 2) / (height * 1.5))`
double fov = 0.6435011087932844;
double pitch = 0.0;
+ double xSkew = 0.0;
+ double ySkew = 1.0;
+ bool axonometric = false;
// cache values for spherical mercator math
double Bc = Projection::worldSize(scale) / util::DEGREES_MAX;
diff --git a/src/mbgl/map/zoom_history.hpp b/src/mbgl/map/zoom_history.hpp
index ddec53e6af..7821499d72 100644
--- a/src/mbgl/map/zoom_history.hpp
+++ b/src/mbgl/map/zoom_history.hpp
@@ -29,7 +29,7 @@ struct ZoomHistory {
if (lastFloorZoom > floorZ) {
lastIntegerZoom = floorZ + 1;
lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now;
- } else if (lastFloorZoom < floorZ || lastIntegerZoom != floorZ) {
+ } else if (lastFloorZoom < floorZ) {
lastIntegerZoom = floorZ;
lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now;
}
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
index 3a38453d30..d023ec7d83 100644
--- a/src/mbgl/programs/attributes.hpp
+++ b/src/mbgl/programs/attributes.hpp
@@ -23,7 +23,7 @@ inline uint16_t packUint8Pair(T a, T b) {
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude);
MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset);
-MBGL_DEFINE_ATTRIBUTE(int16_t, 3, a_pos_normal);
+MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_normal);
MBGL_DEFINE_ATTRIBUTE(float, 3, a_projected_pos);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_label_pos);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_anchor_pos);
diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp
index f9e91f569f..faf57ef19b 100644
--- a/src/mbgl/programs/line_program.cpp
+++ b/src/mbgl/programs/line_program.cpp
@@ -10,7 +10,7 @@ namespace mbgl {
using namespace style;
-static_assert(sizeof(LineLayoutVertex) == 10, "expected LineLayoutVertex size");
+static_assert(sizeof(LineLayoutVertex) == 12, "expected LineLayoutVertex size");
template <class Values, class...Args>
Values makeValues(const RenderLinePaintProperties::PossiblyEvaluated& properties,
diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp
index 95b9362b85..da9964e623 100644
--- a/src/mbgl/programs/line_program.hpp
+++ b/src/mbgl/programs/line_program.hpp
@@ -59,7 +59,8 @@ public:
{{
p.x,
p.y,
- static_cast<int16_t>(attributes::packUint8Pair(round ? 1 : 0, up ? 1 : 0))
+ static_cast<int16_t>(round ? 1 : 0),
+ static_cast<int16_t>(up ? 1 : -1)
}},
{{
// add 128 to store a byte in an unsigned byte
diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp
index 692747bca4..2ef6be0c4f 100644
--- a/src/mbgl/renderer/image_manager.cpp
+++ b/src/mbgl/renderer/image_manager.cpp
@@ -39,6 +39,13 @@ void ImageManager::removeImage(const std::string& id) {
auto it = patterns.find(id);
if (it != patterns.end()) {
+ // Clear pattern from the atlas image.
+ const uint32_t x = it->second.bin->x;
+ const uint32_t y = it->second.bin->y;
+ const uint32_t w = it->second.bin->w;
+ const uint32_t h = it->second.bin->h;
+ PremultipliedImage::clear(atlasImage, { x, y }, { w, h });
+
shelfPack.unref(*it->second.bin);
patterns.erase(it);
}
@@ -52,23 +59,23 @@ const style::Image::Impl* ImageManager::getImage(const std::string& id) const {
return nullptr;
}
-void ImageManager::getImages(ImageRequestor& requestor, ImageDependencies dependencies) {
+void ImageManager::getImages(ImageRequestor& requestor, ImageRequestPair&& pair) {
// If the sprite has been loaded, or if all the icon dependencies are already present
// (i.e. if they've been addeded via runtime styling), then notify the requestor immediately.
// Otherwise, delay notification until the sprite is loaded. At that point, if any of the
// dependencies are still unavailable, we'll just assume they are permanently missing.
bool hasAllDependencies = true;
if (!isLoaded()) {
- for (const auto& dependency : dependencies) {
+ for (const auto& dependency : pair.first) {
if (images.find(dependency) == images.end()) {
hasAllDependencies = false;
}
}
}
if (isLoaded() || hasAllDependencies) {
- notify(requestor, dependencies);
+ notify(requestor, std::move(pair));
} else {
- requestors.emplace(&requestor, std::move(dependencies));
+ requestors.emplace(&requestor, std::move(pair));
}
}
@@ -76,17 +83,17 @@ void ImageManager::removeRequestor(ImageRequestor& requestor) {
requestors.erase(&requestor);
}
-void ImageManager::notify(ImageRequestor& requestor, const ImageDependencies& dependencies) const {
+void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pair) const {
ImageMap response;
- for (const auto& dependency : dependencies) {
+ for (const auto& dependency : pair.first) {
auto it = images.find(dependency);
if (it != images.end()) {
response.emplace(*it);
}
}
- requestor.onImagesAvailable(response);
+ requestor.onImagesAvailable(response, pair.second);
}
void ImageManager::dumpDebugLogs() const {
diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp
index 1c9d67f47d..f72ba9fb53 100644
--- a/src/mbgl/renderer/image_manager.hpp
+++ b/src/mbgl/renderer/image_manager.hpp
@@ -21,7 +21,7 @@ class Context;
class ImageRequestor {
public:
virtual ~ImageRequestor() = default;
- virtual void onImagesAvailable(ImageMap) = 0;
+ virtual void onImagesAvailable(ImageMap, uint64_t imageCorrelationID) = 0;
};
/*
@@ -50,15 +50,15 @@ public:
void updateImage(Immutable<style::Image::Impl>);
void removeImage(const std::string&);
- void getImages(ImageRequestor&, ImageDependencies);
+ void getImages(ImageRequestor&, ImageRequestPair&&);
void removeRequestor(ImageRequestor&);
private:
- void notify(ImageRequestor&, const ImageDependencies&) const;
+ void notify(ImageRequestor&, const ImageRequestPair&) const;
bool loaded = false;
- std::unordered_map<ImageRequestor*, ImageDependencies> requestors;
+ std::unordered_map<ImageRequestor*, ImageRequestPair> requestors;
ImageMap images;
// Pattern stuff
diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp
index ae0c4b026b..7ece3970da 100644
--- a/src/mbgl/renderer/layers/render_custom_layer.cpp
+++ b/src/mbgl/renderer/layers/render_custom_layer.cpp
@@ -16,8 +16,12 @@ RenderCustomLayer::RenderCustomLayer(Immutable<style::CustomLayer::Impl> _impl)
RenderCustomLayer::~RenderCustomLayer() {
assert(BackendScope::exists());
- if (initialized && impl().deinitializeFn) {
- impl().deinitializeFn(impl().context);
+ if (initialized) {
+ if (contextDestroyed && impl().contextLostFn ) {
+ impl().contextLostFn(impl().context);
+ } else if (!contextDestroyed && impl().deinitializeFn) {
+ impl().deinitializeFn(impl().context);
+ }
}
}
diff --git a/src/mbgl/renderer/layers/render_custom_layer.hpp b/src/mbgl/renderer/layers/render_custom_layer.hpp
index d8e9d93811..32ed9da8da 100644
--- a/src/mbgl/renderer/layers/render_custom_layer.hpp
+++ b/src/mbgl/renderer/layers/render_custom_layer.hpp
@@ -19,8 +19,13 @@ public:
const style::CustomLayer::Impl& impl() const;
+ void markContextDestroyed() {
+ contextDestroyed = true;
+ };
+
private:
bool initialized = false;
+ bool contextDestroyed = false;
};
template <>
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
index 6295f62b21..fbd6160e8a 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -37,8 +37,9 @@ void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters
void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) {
evaluated = unevaluated.evaluate(parameters);
- passes = (evaluated.get<style::FillExtrusionOpacity>() > 0) ? RenderPass::Translucent
- : RenderPass::None;
+ passes = (evaluated.get<style::FillExtrusionOpacity>() > 0)
+ ? (RenderPass::Translucent | RenderPass::Pass3D)
+ : RenderPass::None;
}
bool RenderFillExtrusionLayer::hasTransition() const {
@@ -50,113 +51,100 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
return;
}
- const auto size = parameters.context.viewport.getCurrentValue().size;
+ if (parameters.pass == RenderPass::Pass3D) {
+ const auto& size = parameters.staticData.backendSize;
- if (!parameters.staticData.extrusionTexture || parameters.staticData.extrusionTexture->getSize() != size) {
- parameters.staticData.extrusionTexture = OffscreenTexture(parameters.context, size, OffscreenTextureAttachment::Depth);
- }
-
- parameters.staticData.extrusionTexture->bind();
-
- parameters.context.setStencilMode(gl::StencilMode::disabled());
- parameters.context.setDepthMode(parameters.depthModeForSublayer(0, gl::DepthMode::ReadWrite));
- parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, 1.0f, {});
-
- if (evaluated.get<FillExtrusionPattern>().from.empty()) {
- for (const RenderTile& tile : renderTiles) {
- assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
- FillExtrusionBucket& bucket = *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
-
- parameters.programs.fillExtrusion.get(evaluated).draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadWrite),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
- FillExtrusionUniforms::values(
- tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
- evaluated.get<FillExtrusionTranslateAnchor>(),
- parameters.state),
- parameters.state,
- parameters.evaluatedLight
- ),
- *bucket.vertexBuffer,
- *bucket.indexBuffer,
- bucket.triangleSegments,
- bucket.paintPropertyBinders.at(getID()),
- evaluated,
- parameters.state.getZoom(),
- getID());
+ if (!renderTexture || renderTexture->getSize() != size) {
+ renderTexture = OffscreenTexture(parameters.context, size, *parameters.staticData.depthRenderbuffer);
}
- } else {
- optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().from);
- optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().to);
- if (!imagePosA || !imagePosB) {
- return;
+ renderTexture->bind();
+
+ optional<float> depthClearValue = {};
+ if (parameters.staticData.depthRenderbuffer->needsClearing()) depthClearValue = 1.0;
+ // Flag the depth buffer as no longer needing to be cleared for the remainder of this pass.
+ parameters.staticData.depthRenderbuffer->shouldClear(false);
+
+ parameters.context.setStencilMode(gl::StencilMode::disabled());
+ parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {});
+
+ if (evaluated.get<FillExtrusionPattern>().from.empty()) {
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
+ FillExtrusionBucket& bucket =
+ *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
+
+ parameters.programs.fillExtrusion.get(evaluated).draw(
+ parameters.context, gl::Triangles(),
+ parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
+ gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ FillExtrusionUniforms::values(
+ tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
+ evaluated.get<FillExtrusionTranslateAnchor>(),
+ parameters.state),
+ parameters.state, parameters.evaluatedLight),
+ *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
+ bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
+ getID());
+ }
+ } else {
+ optional<ImagePosition> imagePosA =
+ parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().from);
+ optional<ImagePosition> imagePosB =
+ parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().to);
+
+ if (!imagePosA || !imagePosB) {
+ return;
+ }
+
+ parameters.imageManager.bind(parameters.context, 0);
+
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
+ FillExtrusionBucket& bucket =
+ *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
+
+ parameters.programs.fillExtrusionPattern.get(evaluated).draw(
+ parameters.context, gl::Triangles(),
+ parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
+ gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ FillExtrusionPatternUniforms::values(
+ tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
+ evaluated.get<FillExtrusionTranslateAnchor>(),
+ parameters.state),
+ parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB,
+ evaluated.get<FillExtrusionPattern>(), tile.id, parameters.state,
+ -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
+ parameters.evaluatedLight),
+ *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
+ bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
+ getID());
+ }
}
- parameters.imageManager.bind(parameters.context, 0);
-
- for (const RenderTile& tile : renderTiles) {
- assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
- FillExtrusionBucket& bucket = *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
-
- parameters.programs.fillExtrusionPattern.get(evaluated).draw(
- parameters.context,
- gl::Triangles(),
- parameters.depthModeForSublayer(0, gl::DepthMode::ReadWrite),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
- FillExtrusionPatternUniforms::values(
- tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
- evaluated.get<FillExtrusionTranslateAnchor>(),
- parameters.state),
- parameters.imageManager.getPixelSize(),
- *imagePosA,
- *imagePosB,
- evaluated.get<FillExtrusionPattern>(),
- tile.id,
- parameters.state,
- -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
- parameters.evaluatedLight
- ),
- *bucket.vertexBuffer,
- *bucket.indexBuffer,
- bucket.triangleSegments,
- bucket.paintPropertyBinders.at(getID()),
- evaluated,
- parameters.state.getZoom(),
- getID());
- }
- }
+ } else if (parameters.pass == RenderPass::Translucent) {
+ parameters.context.bindTexture(renderTexture->getTexture());
- parameters.backend.bind();
- parameters.context.bindTexture(parameters.staticData.extrusionTexture->getTexture());
-
- mat4 viewportMat;
- matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
-
- const Properties<>::PossiblyEvaluated properties;
-
- parameters.programs.extrusionTexture.draw(
- parameters.context,
- gl::Triangles(),
- gl::DepthMode::disabled(),
- gl::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
- ExtrusionTextureProgram::UniformValues{
- uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
- uniforms::u_image::Value{ 0 },
- uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() }
- },
- parameters.staticData.extrusionTextureVertexBuffer,
- parameters.staticData.quadTriangleIndexBuffer,
- parameters.staticData.extrusionTextureSegments,
- ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 },
- properties,
- parameters.state.getZoom(),
- getID());
+ const auto& size = parameters.staticData.backendSize;
+
+ mat4 viewportMat;
+ matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
+
+ const Properties<>::PossiblyEvaluated properties;
+
+ parameters.programs.extrusionTexture.draw(
+ parameters.context, gl::Triangles(), gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ ExtrusionTextureProgram::UniformValues{
+ uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
+ uniforms::u_image::Value{ 0 },
+ uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() } },
+ parameters.staticData.extrusionTextureVertexBuffer,
+ parameters.staticData.quadTriangleIndexBuffer,
+ parameters.staticData.extrusionTextureSegments,
+ ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties,
+ parameters.state.getZoom(), getID());
+ }
}
bool RenderFillExtrusionLayer::queryIntersectsFeature(
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
index a53e00ca6f..838494cf91 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
@@ -3,6 +3,8 @@
#include <mbgl/renderer/render_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/offscreen_texture.hpp>
namespace mbgl {
@@ -30,6 +32,8 @@ public:
style::FillExtrusionPaintProperties::PossiblyEvaluated evaluated;
const style::FillExtrusionLayer::Impl& impl() const;
+
+ optional<OffscreenTexture> renderTexture;
};
template <>
diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp
index 394642a50d..22cb9563c1 100644
--- a/src/mbgl/renderer/layers/render_fill_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.cpp
@@ -99,7 +99,9 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
&& evaluated.get<FillOpacity>().constantOr(0) >= 1.0f) == (parameters.pass == RenderPass::Opaque)) {
draw(parameters.programs.fill,
gl::Triangles(),
- parameters.depthModeForSublayer(1, gl::DepthMode::ReadWrite),
+ parameters.depthModeForSublayer(1, parameters.pass == RenderPass::Opaque
+ ? gl::DepthMode::ReadWrite
+ : gl::DepthMode::ReadOnly),
*bucket.triangleIndexBuffer,
bucket.triangleSegments);
}
diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp
index ebdaecd3a3..299db844bc 100644
--- a/src/mbgl/renderer/paint_parameters.cpp
+++ b/src/mbgl/renderer/paint_parameters.cpp
@@ -1,6 +1,5 @@
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/update_parameters.hpp>
-#include <mbgl/renderer/render_style.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/map/transform_state.hpp>
@@ -11,17 +10,19 @@ PaintParameters::PaintParameters(gl::Context& context_,
GLContextMode contextMode_,
RendererBackend& backend_,
const UpdateParameters& updateParameters,
- RenderStyle& style,
+ const EvaluatedLight& evaluatedLight_,
RenderStaticData& staticData_,
- FrameHistory& frameHistory_)
+ FrameHistory& frameHistory_,
+ ImageManager& imageManager_,
+ LineAtlas& lineAtlas_)
: context(context_),
backend(backend_),
state(updateParameters.transformState),
- evaluatedLight(style.getRenderLight().getEvaluated()),
+ evaluatedLight(evaluatedLight_),
staticData(staticData_),
frameHistory(frameHistory_),
- imageManager(*style.imageManager),
- lineAtlas(*style.lineAtlas),
+ imageManager(imageManager_),
+ lineAtlas(lineAtlas_),
mapMode(updateParameters.mode),
debugOptions(updateParameters.debugOptions),
contextMode(contextMode_),
@@ -61,6 +62,10 @@ gl::DepthMode PaintParameters::depthModeForSublayer(uint8_t n, gl::DepthMode::Ma
return gl::DepthMode { gl::DepthMode::LessEqual, mask, { nearDepth, farDepth } };
}
+gl::DepthMode PaintParameters::depthModeFor3D(gl::DepthMode::Mask mask) const {
+ return gl::DepthMode { gl::DepthMode::LessEqual, mask, { 0.0, 1.0 } };
+}
+
gl::StencilMode PaintParameters::stencilModeForClipping(const ClipID& id) const {
return gl::StencilMode {
gl::StencilMode::Equal { static_cast<uint32_t>(id.mask.to_ulong()) },
diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp
index e9d3562a75..4a2c2c6f12 100644
--- a/src/mbgl/renderer/paint_parameters.hpp
+++ b/src/mbgl/renderer/paint_parameters.hpp
@@ -15,7 +15,6 @@ namespace mbgl {
class RendererBackend;
class UpdateParameters;
-class RenderStyle;
class RenderStaticData;
class FrameHistory;
class Programs;
@@ -31,9 +30,11 @@ public:
GLContextMode,
RendererBackend&,
const UpdateParameters&,
- RenderStyle&,
+ const EvaluatedLight&,
RenderStaticData&,
- FrameHistory&);
+ FrameHistory&,
+ ImageManager&,
+ LineAtlas&);
gl::Context& context;
RendererBackend& backend;
@@ -59,6 +60,7 @@ public:
Programs& programs;
gl::DepthMode depthModeForSublayer(uint8_t n, gl::DepthMode::Mask) const;
+ gl::DepthMode depthModeFor3D(gl::DepthMode::Mask) const;
gl::StencilMode stencilModeForClipping(const ClipID&) const;
gl::ColorMode colorModeForRenderPass() const;
diff --git a/src/mbgl/renderer/render_pass.hpp b/src/mbgl/renderer/render_pass.hpp
index ae2b923ba1..5d18304129 100644
--- a/src/mbgl/renderer/render_pass.hpp
+++ b/src/mbgl/renderer/render_pass.hpp
@@ -11,6 +11,7 @@ enum class RenderPass : uint8_t {
None = 0,
Opaque = 1 << 0,
Translucent = 1 << 1,
+ Pass3D = 1 << 2,
};
MBGL_CONSTEXPR RenderPass operator|(RenderPass a, RenderPass b) {
diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp
index b565439588..8293923ff6 100644
--- a/src/mbgl/renderer/render_source.hpp
+++ b/src/mbgl/renderer/render_source.hpp
@@ -18,7 +18,6 @@ namespace mbgl {
class PaintParameters;
class TransformState;
class RenderTile;
-class RenderStyle;
class RenderLayer;
class RenderedQueryOptions;
class SourceQueryOptions;
@@ -63,7 +62,7 @@ public:
virtual std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const = 0;
virtual std::vector<Feature>
diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp
index 07a47b4c8f..cf58c31f4d 100644
--- a/src/mbgl/renderer/render_static_data.hpp
+++ b/src/mbgl/renderer/render_static_data.hpp
@@ -4,7 +4,6 @@
#include <mbgl/gl/index_buffer.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/util/optional.hpp>
-#include <mbgl/util/offscreen_texture.hpp>
#include <string>
@@ -26,7 +25,9 @@ public:
SegmentVector<RasterAttributes> rasterSegments;
SegmentVector<ExtrusionTextureAttributes> extrusionTextureSegments;
- optional<OffscreenTexture> extrusionTexture;
+ optional<gl::Renderbuffer<gl::RenderbufferType::DepthComponent>> depthRenderbuffer;
+ bool has3D = false;
+ Size backendSize;
Programs programs;
diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp
index b498972f5c..3db02393d2 100644
--- a/src/mbgl/renderer/render_tile.hpp
+++ b/src/mbgl/renderer/render_tile.hpp
@@ -28,6 +28,7 @@ public:
mat4 matrix;
mat4 nearClippedMatrix;
bool used = false;
+ bool needsClipping = false;
mat4 translatedMatrix(const std::array<float, 2>& translate,
style::TranslateAnchorType anchor,
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
index 9f4b897d6e..e915f5e146 100644
--- a/src/mbgl/renderer/renderer.cpp
+++ b/src/mbgl/renderer/renderer.cpp
@@ -1,6 +1,6 @@
#include <mbgl/renderer/renderer.hpp>
#include <mbgl/renderer/renderer_impl.hpp>
-#include <mbgl/renderer/update_parameters.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
namespace mbgl {
@@ -15,7 +15,14 @@ Renderer::Renderer(RendererBackend& backend,
contextMode_, std::move(programCacheDir_))) {
}
-Renderer::~Renderer() = default;
+Renderer::~Renderer() {
+ BackendScope guard { impl->backend };
+ impl.reset();
+}
+
+void Renderer::markContextLost() {
+ impl->markContextLost();
+}
void Renderer::setObserver(RendererObserver* observer) {
impl->setObserver(observer);
@@ -72,6 +79,7 @@ void Renderer::dumpDebugLogs() {
}
void Renderer::onLowMemory() {
+ BackendScope guard { impl->backend };
impl->onLowMemory();
}
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index dd3c0d41a1..6a8c18792e 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -1,13 +1,32 @@
+#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/renderer/renderer_impl.hpp>
-#include <mbgl/renderer/render_style.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/renderer/renderer_observer.hpp>
+#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_layer.hpp>
#include <mbgl/renderer/render_static_data.hpp>
-#include <mbgl/renderer/render_item.hpp>
#include <mbgl/renderer/update_parameters.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/transition_parameters.hpp>
+#include <mbgl/renderer/property_evaluation_parameters.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/style_diff.hpp>
+#include <mbgl/renderer/query.hpp>
#include <mbgl/renderer/backend_scope.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/gl/debugging.hpp>
#include <mbgl/geometry/line_atlas.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/text/glyph_manager.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
@@ -24,20 +43,36 @@ Renderer::Impl::Impl(RendererBackend& backend_,
Scheduler& scheduler_,
GLContextMode contextMode_,
const optional<std::string> programCacheDir_)
- : backend(backend_)
- , observer(&nullObserver())
- , contextMode(contextMode_)
- , pixelRatio(pixelRatio_)
- , programCacheDir(programCacheDir_)
- , renderStyle(std::make_unique<RenderStyle>(scheduler_, fileSource_)) {
-
- renderStyle->setObserver(this);
+ : backend(backend_)
+ , scheduler(scheduler_)
+ , fileSource(fileSource_)
+ , observer(&nullObserver())
+ , contextMode(contextMode_)
+ , pixelRatio(pixelRatio_)
+ , programCacheDir(programCacheDir_)
+ , glyphManager(std::make_unique<GlyphManager>(fileSource))
+ , imageManager(std::make_unique<ImageManager>())
+ , lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 }))
+ , imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>())
+ , sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>())
+ , layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>())
+ , renderLight(makeMutable<Light::Impl>()) {
+ glyphManager->setObserver(this);
}
Renderer::Impl::~Impl() {
- BackendScope guard { backend };
- renderStyle.reset();
- staticData.reset();
+ assert(BackendScope::exists());
+
+ if (contextLost) {
+ // Signal all RenderCustomLayers that the context was lost
+ // before cleaning up
+ for (const auto& entry : renderLayers) {
+ RenderLayer& layer = *entry.second;
+ if (layer.is<RenderCustomLayer>()) {
+ layer.as<RenderCustomLayer>()->markContextDestroyed();
+ }
+ }
+ }
};
void Renderer::Impl::setObserver(RendererObserver* observer_) {
@@ -45,12 +80,164 @@ void Renderer::Impl::setObserver(RendererObserver* observer_) {
}
void Renderer::Impl::render(const UpdateParameters& updateParameters) {
- // Don't load/render anyting in still mode until explicitly requested.
- if (updateParameters.mode == MapMode::Still && !updateParameters.stillImageRequest) return;
+ if (updateParameters.mode == MapMode::Still) {
+ // Don't load/render anyting in still mode until explicitly requested.
+ if (!updateParameters.stillImageRequest) {
+ return;
+ }
+
+ // Reset zoom history state.
+ zoomHistory.first = true;
+ }
assert(BackendScope::exists());
+
+ updateParameters.annotationManager.updateData();
+
+ const bool zoomChanged = zoomHistory.update(updateParameters.transformState.getZoom(), updateParameters.timePoint);
+
+ const TransitionParameters transitionParameters {
+ updateParameters.timePoint,
+ updateParameters.mode == MapMode::Continuous ? updateParameters.transitionOptions : TransitionOptions()
+ };
+
+ const PropertyEvaluationParameters evaluationParameters {
+ zoomHistory,
+ updateParameters.timePoint,
+ updateParameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero()
+ };
+
+ const TileParameters tileParameters {
+ updateParameters.pixelRatio,
+ updateParameters.debugOptions,
+ updateParameters.transformState,
+ scheduler,
+ fileSource,
+ updateParameters.mode,
+ updateParameters.annotationManager,
+ *imageManager,
+ *glyphManager,
+ updateParameters.prefetchZoomDelta
+ };
+
+ glyphManager->setURL(updateParameters.glyphURL);
+
+ // Update light.
+ const bool lightChanged = renderLight.impl != updateParameters.light;
+
+ if (lightChanged) {
+ renderLight.impl = updateParameters.light;
+ renderLight.transition(transitionParameters);
+ }
+
+ if (lightChanged || zoomChanged || renderLight.hasTransition()) {
+ renderLight.evaluate(evaluationParameters);
+ }
+
+
+ const ImageDifference imageDiff = diffImages(imageImpls, updateParameters.images);
+ imageImpls = updateParameters.images;
+
+ // Remove removed images from sprite atlas.
+ for (const auto& entry : imageDiff.removed) {
+ imageManager->removeImage(entry.first);
+ }
+
+ // Add added images to sprite atlas.
+ for (const auto& entry : imageDiff.added) {
+ imageManager->addImage(entry.second);
+ }
+
+ // Update changed images.
+ for (const auto& entry : imageDiff.changed) {
+ imageManager->updateImage(entry.second.after);
+ }
+
+ imageManager->setLoaded(updateParameters.spriteLoaded);
+
+
+ const LayerDifference layerDiff = diffLayers(layerImpls, updateParameters.layers);
+ layerImpls = updateParameters.layers;
+
+ // Remove render layers for removed layers.
+ for (const auto& entry : layerDiff.removed) {
+ renderLayers.erase(entry.first);
+ }
+
+ // Create render layers for newly added layers.
+ for (const auto& entry : layerDiff.added) {
+ renderLayers.emplace(entry.first, RenderLayer::create(entry.second));
+ }
+
+ // Update render layers for changed layers.
+ for (const auto& entry : layerDiff.changed) {
+ renderLayers.at(entry.first)->setImpl(entry.second.after);
+ }
+
+ // Update layers for class and zoom changes.
+ for (const auto& entry : renderLayers) {
+ RenderLayer& layer = *entry.second;
+ const bool layerAdded = layerDiff.added.count(entry.first);
+ const bool layerChanged = layerDiff.changed.count(entry.first);
+
+ if (layerAdded || layerChanged) {
+ layer.transition(transitionParameters);
+ }
+
+ if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) {
+ layer.evaluate(evaluationParameters);
+ }
+ }
+
+
+ const SourceDifference sourceDiff = diffSources(sourceImpls, updateParameters.sources);
+ sourceImpls = updateParameters.sources;
+
+ // Remove render layers for removed sources.
+ for (const auto& entry : sourceDiff.removed) {
+ renderSources.erase(entry.first);
+ }
+
+ // Create render sources for newly added sources.
+ for (const auto& entry : sourceDiff.added) {
+ std::unique_ptr<RenderSource> renderSource = RenderSource::create(entry.second);
+ renderSource->setObserver(this);
+ renderSources.emplace(entry.first, std::move(renderSource));
+ }
+
+ const bool hasImageDiff = !(imageDiff.added.empty() && imageDiff.removed.empty() && imageDiff.changed.empty());
+
+ // Update all sources.
+ for (const auto& source : *sourceImpls) {
+ std::vector<Immutable<Layer::Impl>> filteredLayers;
+ bool needsRendering = false;
+ bool needsRelayout = false;
+
+ for (const auto& layer : *layerImpls) {
+ if (layer->type == LayerType::Background ||
+ layer->type == LayerType::Custom ||
+ layer->source != source->id) {
+ continue;
+ }
+
+ if (!needsRendering && getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) {
+ needsRendering = true;
+ }
+
+ if (!needsRelayout && (hasImageDiff || hasLayoutDifference(layerDiff, layer->id))) {
+ needsRelayout = true;
+ }
+
+ filteredLayers.push_back(layer);
+ }
+
+ renderSources.at(source->id)->update(source,
+ filteredLayers,
+ needsRendering,
+ needsRelayout,
+ tileParameters);
+ }
- renderStyle->update(updateParameters);
transformState = updateParameters.transformState;
if (!staticData) {
@@ -63,60 +250,138 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
contextMode,
backend,
updateParameters,
- *renderStyle,
+ renderLight.getEvaluated(),
*staticData,
- frameHistory
+ frameHistory,
+ *imageManager,
+ *lineAtlas
};
- bool loaded = updateParameters.styleLoaded && renderStyle->isLoaded();
+ bool loaded = updateParameters.styleLoaded && isLoaded();
+ if (updateParameters.mode == MapMode::Still && !loaded) {
+ return;
+ }
- if (updateParameters.mode == MapMode::Continuous) {
- if (renderState == RenderState::Never) {
- observer->onWillStartRenderingMap();
- }
+ if (renderState == RenderState::Never) {
+ observer->onWillStartRenderingMap();
+ }
+
+ observer->onWillStartRenderingFrame();
+
+ backend.updateAssumedState();
- observer->onWillStartRenderingFrame();
+ if (parameters.contextMode == GLContextMode::Shared) {
+ parameters.context.setDirtyState();
+ }
- backend.updateAssumedState();
+ Color backgroundColor;
- doRender(parameters);
- parameters.context.performCleanup();
+ class RenderItem {
+ public:
+ RenderLayer& layer;
+ RenderSource* source;
+ };
+
+ std::vector<RenderItem> order;
- observer->onDidFinishRenderingFrame(
- loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
- renderStyle->hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION)
- );
+ for (auto& layerImpl : *layerImpls) {
+ RenderLayer* layer = getRenderLayer(layerImpl->id);
+ assert(layer);
- if (!loaded) {
- renderState = RenderState::Partial;
- } else if (renderState != RenderState::Fully) {
- renderState = RenderState::Fully;
- observer->onDidFinishRenderingMap();
+ if (!parameters.staticData.has3D && layer->is<RenderFillExtrusionLayer>()) {
+ parameters.staticData.has3D = true;
}
- } else if (loaded) {
- observer->onWillStartRenderingMap();
- observer->onWillStartRenderingFrame();
- backend.updateAssumedState();
+ if (!layer->needsRendering(zoomHistory.lastZoom)) {
+ continue;
+ }
- doRender(parameters);
+ if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) {
+ const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated;
+ if (layerImpl.get() == layerImpls->at(0).get() && paint.get<BackgroundPattern>().from.empty()) {
+ // This is a solid background. We can use glClear().
+ backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
+ } else {
+ // This is a textured background, or not the bottommost layer. We need to render it with a quad.
+ order.emplace_back(RenderItem { *layer, nullptr });
+ }
+ continue;
+ }
- observer->onDidFinishRenderingFrame(RendererObserver::RenderMode::Full, false);
- observer->onDidFinishRenderingMap();
+ if (layer->is<RenderCustomLayer>()) {
+ order.emplace_back(RenderItem { *layer, nullptr });
+ continue;
+ }
- // Cleanup only after signaling completion
- parameters.context.performCleanup();
- }
-}
+ RenderSource* source = getRenderSource(layer->baseImpl->source);
+ if (!source) {
+ Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str());
+ continue;
+ }
-void Renderer::Impl::doRender(PaintParameters& parameters) {
- if (parameters.contextMode == GLContextMode::Shared) {
- parameters.context.setDirtyState();
- }
+ const bool symbolLayer = layer->is<RenderSymbolLayer>();
+
+ auto sortedTiles = source->getRenderTiles();
+ if (symbolLayer) {
+ // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn
+ // on top of each other, with lower symbols being drawn on top of higher symbols.
+ std::sort(sortedTiles.begin(), sortedTiles.end(), [&](const RenderTile& a, const RenderTile& b) {
+ Point<float> pa(a.id.canonical.x, a.id.canonical.y);
+ Point<float> pb(b.id.canonical.x, b.id.canonical.y);
- RenderData renderData = renderStyle->getRenderData(parameters.debugOptions, parameters.state.getAngle());
- const std::vector<RenderItem>& order = renderData.order;
- const std::unordered_set<RenderSource*>& sources = renderData.sources;
+ auto par = util::rotate(pa, parameters.state.getAngle());
+ auto pbr = util::rotate(pb, parameters.state.getAngle());
+
+ return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x);
+ });
+ } else {
+ std::sort(sortedTiles.begin(), sortedTiles.end(),
+ [](const auto& a, const auto& b) { return a.get().id < b.get().id; });
+ }
+
+ std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
+ for (auto& sortedTile : sortedTiles) {
+ auto& tile = sortedTile.get();
+ if (!tile.tile.isRenderable()) {
+ continue;
+ }
+
+ // We're not clipping symbol layers, so when we have both parents and children of symbol
+ // layers, we drop all children in favor of their parent to avoid duplicate labels.
+ // See https://github.com/mapbox/mapbox-gl-native/issues/2482
+ if (symbolLayer) {
+ bool skip = false;
+ // Look back through the buckets we decided to render to find out whether there is
+ // already a bucket from this layer that is a parent of this tile. Tiles are ordered
+ // by zoom level when we obtain them from getTiles().
+ for (auto it = sortedTilesForInsertion.rbegin();
+ it != sortedTilesForInsertion.rend(); ++it) {
+ if (tile.tile.id.isChildOf(it->get().tile.id)) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip) {
+ continue;
+ }
+ }
+
+ auto bucket = tile.tile.getBucket(*layer->baseImpl);
+ if (bucket) {
+ 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) {
+ tile.needsClipping = true;
+ }
+ }
+ }
+ layer->setRenderTiles(std::move(sortedTilesForInsertion));
+ order.emplace_back(RenderItem { *layer, source });
+ }
frameHistory.record(parameters.timePoint,
parameters.state.getZoom(),
@@ -130,6 +395,39 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
parameters.imageManager.upload(parameters.context, 0);
parameters.lineAtlas.upload(parameters.context, 0);
parameters.frameHistory.upload(parameters.context, 0);
+
+ // Update all clipping IDs + upload buckets.
+ for (const auto& entry : renderSources) {
+ if (entry.second->isEnabled()) {
+ entry.second->startRender(parameters);
+ }
+ }
+ }
+
+ // - 3D PASS -------------------------------------------------------------------------------------
+ // Renders any 3D layers bottom-to-top to unique FBOs with texture attachments, but share the same
+ // depth rbo between them.
+ if (parameters.staticData.has3D) {
+ parameters.staticData.backendSize = parameters.backend.getFramebufferSize();
+
+ MBGL_DEBUG_GROUP(parameters.context, "3d");
+ parameters.pass = RenderPass::Pass3D;
+
+ if (!parameters.staticData.depthRenderbuffer ||
+ parameters.staticData.depthRenderbuffer->size != parameters.staticData.backendSize) {
+ parameters.staticData.depthRenderbuffer =
+ parameters.context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(parameters.staticData.backendSize);
+ }
+ parameters.staticData.depthRenderbuffer->shouldClear(true);
+
+ uint32_t i = static_cast<uint32_t>(order.size()) - 1;
+ for (auto it = order.begin(); it != order.end(); ++it, --i) {
+ parameters.currentLayer = i;
+ if (it->layer.hasRenderPass(parameters.pass)) {
+ MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
+ it->layer.render(parameters, it->source);
+ }
+ }
}
// - CLEAR -------------------------------------------------------------------------------------
@@ -140,7 +438,7 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
parameters.backend.bind();
parameters.context.clear((parameters.debugOptions & MapDebugOptions::Overdraw)
? Color::black()
- : renderData.backgroundColor,
+ : backgroundColor,
1.0f,
0);
}
@@ -148,13 +446,6 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
// - CLIPPING MASKS ----------------------------------------------------------------------------
// Draws the clipping masks to the stencil buffer.
{
- MBGL_DEBUG_GROUP(parameters.context, "clip");
-
- // Update all clipping IDs.
- for (const auto& source : sources) {
- source->startRender(parameters);
- }
-
MBGL_DEBUG_GROUP(parameters.context, "clipping masks");
static const style::FillPaintProperties::PossiblyEvaluated properties {};
@@ -220,10 +511,7 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
}
#endif
- int indent = 0;
-
// Actually render the layers
- if (debug::renderTree) { Log::Info(Event::Render, "{"); indent++; }
parameters.depthRangeSize = 1 - (order.size() + 2) * parameters.numSublayers * parameters.depthEpsilon;
@@ -233,10 +521,6 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
parameters.pass = RenderPass::Opaque;
MBGL_DEBUG_GROUP(parameters.context, "opaque");
- if (debug::renderTree) {
- Log::Info(Event::Render, "%*s%s {", indent++ * 4, "", "opaque");
- }
-
uint32_t i = 0;
for (auto it = order.rbegin(); it != order.rend(); ++it, ++i) {
parameters.currentLayer = i;
@@ -245,10 +529,6 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
it->layer.render(parameters, it->source);
}
}
-
- if (debug::renderTree) {
- Log::Info(Event::Render, "%*s%s", --indent * 4, "", "}");
- }
}
// - TRANSLUCENT PASS --------------------------------------------------------------------------
@@ -257,10 +537,6 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
parameters.pass = RenderPass::Translucent;
MBGL_DEBUG_GROUP(parameters.context, "translucent");
- if (debug::renderTree) {
- Log::Info(Event::Render, "%*s%s {", indent++ * 4, "", "translucent");
- }
-
uint32_t i = static_cast<uint32_t>(order.size()) - 1;
for (auto it = order.begin(); it != order.end(); ++it, --i) {
parameters.currentLayer = i;
@@ -269,14 +545,8 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
it->layer.render(parameters, it->source);
}
}
-
- if (debug::renderTree) {
- Log::Info(Event::Render, "%*s%s", --indent * 4, "", "}");
- }
}
- if (debug::renderTree) { Log::Info(Event::Render, "}"); indent--; }
-
// - DEBUG PASS --------------------------------------------------------------------------------
// Renders debug overlays.
{
@@ -286,8 +556,10 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
// 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 auto& source : sources) {
- source->finishRender(parameters);
+ for (const auto& entry : renderSources) {
+ if (entry.second->isEnabled()) {
+ entry.second->finishRender(parameters);
+ }
}
}
@@ -319,43 +591,159 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
{
MBGL_DEBUG_GROUP(parameters.context, "cleanup");
- parameters.context.activeTexture = 1;
+ parameters.context.activeTextureUnit = 1;
parameters.context.texture[1] = 0;
- parameters.context.activeTexture = 0;
+ parameters.context.activeTextureUnit = 0;
parameters.context.texture[0] = 0;
parameters.context.bindVertexArray = 0;
}
+
+ observer->onDidFinishRenderingFrame(
+ loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
+ updateParameters.mode == MapMode::Continuous && (hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION))
+ );
+
+ if (!loaded) {
+ renderState = RenderState::Partial;
+ } else if (renderState != RenderState::Fully) {
+ renderState = RenderState::Fully;
+ observer->onDidFinishRenderingMap();
+ }
+
+ // Cleanup only after signaling completion
+ parameters.context.performCleanup();
}
std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const {
- return renderStyle->queryRenderedFeatures(geometry, transformState, options);
+ std::vector<const RenderLayer*> layers;
+ if (options.layerIDs) {
+ for (const auto& layerID : *options.layerIDs) {
+ if (const RenderLayer* layer = getRenderLayer(layerID)) {
+ layers.emplace_back(layer);
+ }
+ }
+ } else {
+ for (const auto& entry : renderLayers) {
+ layers.emplace_back(entry.second.get());
+ }
+ }
+
+ std::unordered_set<std::string> sourceIDs;
+ for (const RenderLayer* layer : layers) {
+ sourceIDs.emplace(layer->baseImpl->source);
+ }
+
+ std::unordered_map<std::string, std::vector<Feature>> resultsByLayer;
+ for (const auto& sourceID : sourceIDs) {
+ if (RenderSource* renderSource = getRenderSource(sourceID)) {
+ auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, layers, options);
+ std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
+ }
+ }
+
+ std::vector<Feature> result;
+
+ if (resultsByLayer.empty()) {
+ return result;
+ }
+
+ // Combine all results based on the style layer order.
+ for (const auto& layerImpl : *layerImpls) {
+ const RenderLayer* layer = getRenderLayer(layerImpl->id);
+ if (!layer->needsRendering(zoomHistory.lastZoom)) {
+ continue;
+ }
+ auto it = resultsByLayer.find(layer->baseImpl->id);
+ if (it != resultsByLayer.end()) {
+ std::move(it->second.begin(), it->second.end(), std::back_inserter(result));
+ }
+ }
+
+ return result;
}
std::vector<Feature> Renderer::Impl::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
- const RenderSource* source = renderStyle->getRenderSource(sourceID);
+ const RenderSource* source = getRenderSource(sourceID);
if (!source) return {};
return source->querySourceFeatures(options);
}
-void Renderer::Impl::onInvalidate() {
+void Renderer::Impl::onLowMemory() {
+ assert(BackendScope::exists());
+ backend.getContext().performCleanup();
+ for (const auto& entry : renderSources) {
+ entry.second->onLowMemory();
+ }
observer->onInvalidate();
}
-void Renderer::Impl::onResourceError(std::exception_ptr ptr) {
- observer->onResourceError(ptr);
+void Renderer::Impl::dumDebugLogs() {
+ for (const auto& entry : renderSources) {
+ entry.second->dumpDebugLogs();
+ }
+
+ imageManager->dumpDebugLogs();
}
-void Renderer::Impl::onLowMemory() {
- BackendScope guard { backend };
- backend.getContext().performCleanup();
- renderStyle->onLowMemory();
- observer->onInvalidate();
+RenderLayer* Renderer::Impl::getRenderLayer(const std::string& id) {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
}
-void Renderer::Impl::dumDebugLogs() {
- renderStyle->dumpDebugLogs();
+const RenderLayer* Renderer::Impl::getRenderLayer(const std::string& id) const {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
+}
+
+RenderSource* Renderer::Impl::getRenderSource(const std::string& id) const {
+ auto it = renderSources.find(id);
+ return it != renderSources.end() ? it->second.get() : nullptr;
+}
+
+bool Renderer::Impl::hasTransitions() const {
+ if (renderLight.hasTransition()) {
+ return true;
+ }
+
+ for (const auto& entry : renderLayers) {
+ if (entry.second->hasTransition()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Renderer::Impl::isLoaded() const {
+ for (const auto& entry: renderSources) {
+ if (!entry.second->isLoaded()) {
+ return false;
+ }
+ }
+
+ if (!imageManager->isLoaded()) {
+ return false;
+ }
+
+ return true;
+}
+
+void Renderer::Impl::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
+ Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s",
+ glyphRange.first, glyphRange.second, fontStackToString(fontStack).c_str(), util::toString(error).c_str());
+ observer->onResourceError(error);
+}
+
+void Renderer::Impl::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) {
+ Log::Error(Event::Style, "Failed to load tile %s for source %s: %s",
+ util::toString(tileID).c_str(), source.baseImpl->id.c_str(), util::toString(error).c_str());
+ observer->onResourceError(error);
+}
+
+void Renderer::Impl::onTileChanged(RenderSource&, const OverscaledTileID&) {
+ observer->onInvalidate();
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 079b00d0bb..30e7f70722 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -1,11 +1,16 @@
#pragma once
#include <mbgl/renderer/renderer.hpp>
-#include <mbgl/renderer/renderer_backend.hpp>
-#include <mbgl/renderer/renderer_observer.hpp>
-#include <mbgl/renderer/render_style_observer.hpp>
+#include <mbgl/renderer/render_source_observer.hpp>
+#include <mbgl/renderer/render_light.hpp>
#include <mbgl/renderer/frame_history.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/layer.hpp>
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/map/zoom_history.hpp>
+#include <mbgl/map/mode.hpp>
+#include <mbgl/text/glyph_manager_observer.hpp>
#include <memory>
#include <string>
@@ -13,17 +18,31 @@
namespace mbgl {
+class RendererBackend;
+class RendererObserver;
+class RenderSource;
+class RenderLayer;
class UpdateParameters;
-class PaintParameters;
-class RenderStyle;
class RenderStaticData;
-
-class Renderer::Impl : public RenderStyleObserver {
+class RenderedQueryOptions;
+class SourceQueryOptions;
+class FileSource;
+class Scheduler;
+class GlyphManager;
+class ImageManager;
+class LineAtlas;
+
+class Renderer::Impl : public GlyphManagerObserver,
+ public RenderSourceObserver{
public:
Impl(RendererBackend&, float pixelRatio_, FileSource&, Scheduler&, GLContextMode,
const optional<std::string> programCacheDir);
~Impl() final;
+ void markContextLost() {
+ contextLost = true;
+ };
+
void setObserver(RendererObserver*);
void render(const UpdateParameters&);
@@ -34,16 +53,28 @@ public:
void onLowMemory();
void dumDebugLogs();
- // RenderStyleObserver implementation
- void onInvalidate() override;
- void onResourceError(std::exception_ptr) override;
-
private:
- void doRender(PaintParameters&);
+ bool isLoaded() const;
+ bool hasTransitions() const;
+
+ RenderSource* getRenderSource(const std::string& id) const;
+
+ RenderLayer* getRenderLayer(const std::string& id);
+ const RenderLayer* getRenderLayer(const std::string& id) const;
+
+ // GlyphManagerObserver implementation.
+ void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override;
+
+ // RenderSourceObserver implementation.
+ void onTileChanged(RenderSource&, const OverscaledTileID&) override;
+ void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
friend class Renderer;
RendererBackend& backend;
+ Scheduler& scheduler;
+ FileSource& fileSource;
+
RendererObserver* observer;
const GLContextMode contextMode;
@@ -58,10 +89,23 @@ private:
RenderState renderState = RenderState::Never;
FrameHistory frameHistory;
+ ZoomHistory zoomHistory;
TransformState transformState;
- std::unique_ptr<RenderStyle> renderStyle;
+ std::unique_ptr<GlyphManager> glyphManager;
+ std::unique_ptr<ImageManager> imageManager;
+ std::unique_ptr<LineAtlas> lineAtlas;
std::unique_ptr<RenderStaticData> staticData;
+
+ Immutable<std::vector<Immutable<style::Image::Impl>>> imageImpls;
+ Immutable<std::vector<Immutable<style::Source::Impl>>> sourceImpls;
+ Immutable<std::vector<Immutable<style::Layer::Impl>>> layerImpls;
+
+ std::unordered_map<std::string, std::unique_ptr<RenderSource>> renderSources;
+ std::unordered_map<std::string, std::unique_ptr<RenderLayer>> renderLayers;
+ RenderLight renderLight;
+
+ bool contextLost = false;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index df8bcc0ae7..504db78ea3 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.cpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.cpp
@@ -2,6 +2,7 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/tile/geojson_tile.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
@@ -34,19 +35,26 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
GeoJSONData* data_ = impl().getData();
- if (!data_) {
- return;
- }
-
if (data_ != data) {
data = data_;
tilePyramid.cache.clear();
- for (auto const& item : tilePyramid.tiles) {
- static_cast<GeoJSONTile*>(item.second.get())->updateData(data->getTile(item.first.canonical));
+ if (data) {
+ const uint8_t maxZ = impl().getZoomRange().max;
+ for (const auto& pair : tilePyramid.tiles) {
+ if (pair.first.canonical.z <= maxZ) {
+ static_cast<GeoJSONTile*>(pair.second.get())->updateData(data->getTile(pair.first.canonical));
+ }
+ }
}
}
+ if (!data) {
+ tilePyramid.tiles.clear();
+ tilePyramid.renderTiles.clear();
+ return;
+ }
+
tilePyramid.update(layers,
needsRendering,
needsRelayout,
@@ -75,9 +83,9 @@ std::vector<std::reference_wrapper<RenderTile>> RenderGeoJSONSource::getRenderTi
std::unordered_map<std::string, std::vector<Feature>>
RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options);
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options);
}
std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryOptions& options) const {
diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp
index b84156ab95..b2e06c68d4 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.hpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.hpp
@@ -30,7 +30,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
@@ -48,7 +48,7 @@ private:
template <>
inline bool RenderSource::is<RenderGeoJSONSource>() const {
- return baseImpl->type == SourceType::GeoJSON;
+ return baseImpl->type == style::SourceType::GeoJSON;
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp
index 50d5b17ec2..9140e01711 100644
--- a/src/mbgl/renderer/sources/render_image_source.cpp
+++ b/src/mbgl/renderer/sources/render_image_source.cpp
@@ -83,7 +83,7 @@ void RenderImageSource::finishRender(PaintParameters& parameters) {
std::unordered_map<std::string, std::vector<Feature>>
RenderImageSource::queryRenderedFeatures(const ScreenLineString&,
const TransformState&,
- const RenderStyle&,
+ const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&) const {
return std::unordered_map<std::string, std::vector<Feature>> {};
}
diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp
index fc1a462090..8d80838c3b 100644
--- a/src/mbgl/renderer/sources/render_image_source.hpp
+++ b/src/mbgl/renderer/sources/render_image_source.hpp
@@ -31,7 +31,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const final;
std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final;
@@ -52,7 +52,7 @@ private:
template <>
inline bool RenderSource::is<RenderImageSource>() const {
- return baseImpl->type == SourceType::Image;
+ return baseImpl->type == style::SourceType::Image;
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp
index cbd874f647..bcd719365d 100644
--- a/src/mbgl/renderer/sources/render_raster_source.cpp
+++ b/src/mbgl/renderer/sources/render_raster_source.cpp
@@ -73,7 +73,7 @@ std::vector<std::reference_wrapper<RenderTile>> RenderRasterSource::getRenderTil
std::unordered_map<std::string, std::vector<Feature>>
RenderRasterSource::queryRenderedFeatures(const ScreenLineString&,
const TransformState&,
- const RenderStyle&,
+ const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&) const {
return std::unordered_map<std::string, std::vector<Feature>> {};
}
diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp
index 1f4678da9f..e1bf5798ff 100644
--- a/src/mbgl/renderer/sources/render_raster_source.hpp
+++ b/src/mbgl/renderer/sources/render_raster_source.hpp
@@ -26,7 +26,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
@@ -44,7 +44,7 @@ private:
template <>
inline bool RenderSource::is<RenderRasterSource>() const {
- return baseImpl->type == SourceType::Raster;
+ return baseImpl->type == style::SourceType::Raster;
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp
index 47bccdaca8..ca3071c6b0 100644
--- a/src/mbgl/renderer/sources/render_vector_source.cpp
+++ b/src/mbgl/renderer/sources/render_vector_source.cpp
@@ -76,9 +76,9 @@ std::vector<std::reference_wrapper<RenderTile>> RenderVectorSource::getRenderTil
std::unordered_map<std::string, std::vector<Feature>>
RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options);
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options);
}
std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOptions& options) const {
diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp
index 256ad4e800..ac319a167e 100644
--- a/src/mbgl/renderer/sources/render_vector_source.hpp
+++ b/src/mbgl/renderer/sources/render_vector_source.hpp
@@ -26,7 +26,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const final;
std::vector<Feature>
@@ -44,7 +44,7 @@ private:
template <>
inline bool RenderSource::is<RenderVectorSource>() const {
- return baseImpl->type == SourceType::Vector;
+ return baseImpl->type == style::SourceType::Vector;
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index 219f154675..3e2311089d 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -121,7 +121,7 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
// we're actively using, e.g. as a replacement for tile that aren't loaded yet.
std::set<OverscaledTileID> retain;
- auto retainTileFn = [&](Tile& tile, Resource::Necessity necessity) -> void {
+ auto retainTileFn = [&](Tile& tile, TileNecessity necessity) -> void {
if (retain.emplace(tile.id).second) {
tile.setNecessity(necessity);
}
@@ -171,7 +171,26 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
cache.setSize(conservativeCacheSize);
}
- removeStaleTiles(retain);
+ // Remove stale tiles. This goes through the (sorted!) tiles map and retain set in lockstep
+ // and removes items from tiles that don't have the corresponding key in the retain set.
+ {
+ auto tilesIt = tiles.begin();
+ auto retainIt = retain.begin();
+ while (tilesIt != tiles.end()) {
+ if (retainIt == retain.end() || tilesIt->first < *retainIt) {
+ if (!needsRelayout) {
+ tilesIt->second->setNecessity(TileNecessity::Optional);
+ cache.add(tilesIt->first, std::move(tilesIt->second));
+ }
+ tiles.erase(tilesIt++);
+ } else {
+ if (!(*retainIt < tilesIt->first)) {
+ ++tilesIt;
+ }
+ ++retainIt;
+ }
+ }
+ }
for (auto& pair : tiles) {
const PlacementConfig config { parameters.transformState.getAngle(),
@@ -184,29 +203,9 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
}
}
-// Moves all tiles to the cache except for those specified in the retain set.
-void TilePyramid::removeStaleTiles(const std::set<OverscaledTileID>& retain) {
- // Remove stale tiles. This goes through the (sorted!) tiles map and retain set in lockstep
- // and removes items from tiles that don't have the corresponding key in the retain set.
- auto tilesIt = tiles.begin();
- auto retainIt = retain.begin();
- while (tilesIt != tiles.end()) {
- if (retainIt == retain.end() || tilesIt->first < *retainIt) {
- tilesIt->second->setNecessity(Tile::Necessity::Optional);
- cache.add(tilesIt->first, std::move(tilesIt->second));
- tiles.erase(tilesIt++);
- } else {
- if (!(*retainIt < tilesIt->first)) {
- ++tilesIt;
- }
- ++retainIt;
- }
- }
-}
-
std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) const {
std::unordered_map<std::string, std::vector<Feature>> result;
if (renderTiles.empty() || geometry.empty()) {
@@ -249,7 +248,7 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
renderTile.tile.queryRenderedFeatures(result,
tileSpaceQueryGeometry,
transformState,
- style,
+ layers,
options);
}
diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp
index d940f378fa..ac4572b103 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -21,7 +21,7 @@ namespace mbgl {
class PaintParameters;
class TransformState;
class RenderTile;
-class RenderStyle;
+class RenderLayer;
class RenderedQueryOptions;
class SourceQueryOptions;
class TileParameters;
@@ -37,7 +37,7 @@ public:
bool needsRendering,
bool needsRelayout,
const TileParameters&,
- SourceType type,
+ style::SourceType type,
uint16_t tileSize,
Range<uint8_t> zoomRange,
std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile);
@@ -50,7 +50,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>&,
const RenderedQueryOptions& options) const;
std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const;
@@ -63,8 +63,6 @@ public:
bool enabled = false;
- void removeStaleTiles(const std::set<OverscaledTileID>&);
-
std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
TileCache cache;
diff --git a/src/mbgl/renderer/update_parameters.hpp b/src/mbgl/renderer/update_parameters.hpp
index 181b11784d..b54abc050d 100644
--- a/src/mbgl/renderer/update_parameters.hpp
+++ b/src/mbgl/renderer/update_parameters.hpp
@@ -13,8 +13,6 @@
namespace mbgl {
-class Scheduler;
-class FileSource;
class AnnotationManager;
class UpdateParameters {
@@ -34,8 +32,6 @@ public:
const Immutable<std::vector<Immutable<style::Source::Impl>>> sources;
const Immutable<std::vector<Immutable<style::Layer::Impl>>> layers;
- Scheduler& scheduler;
- FileSource& fileSource;
AnnotationManager& annotationManager;
const uint8_t prefetchZoomDelta;
diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp
index f68cc91377..c700295a15 100644
--- a/src/mbgl/shaders/line.cpp
+++ b/src/mbgl/shaders/line.cpp
@@ -21,7 +21,7 @@ const char* line::vertexSource = R"MBGL_SHADER(
// #define scale 63.0
#define scale 0.015873016
-attribute vec3 a_pos_normal;
+attribute vec4 a_pos_normal;
attribute vec4 a_data;
uniform mat4 u_matrix;
@@ -133,12 +133,9 @@ void main() {
vec2 pos = a_pos_normal.xy;
- // transform y normal so that 0 => -1 and 1 => 1
- // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // x is 1 if it's a round cap, 0 otherwise
// y is 1 if the normal points up, and -1 if it points down
- mediump vec2 normal = unpack_float(a_pos_normal.z);
- normal.y = sign(normal.y - 0.5);
-
+ mediump vec2 normal = a_pos_normal.zw;
v_normal = normal;
// these transformations used to be applied in the JS and native code bases.
diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp
index f1e64577e2..f8d785ade9 100644
--- a/src/mbgl/shaders/line_pattern.cpp
+++ b/src/mbgl/shaders/line_pattern.cpp
@@ -23,7 +23,7 @@ const char* line_pattern::vertexSource = R"MBGL_SHADER(
// Retina devices need a smaller distance to avoid aliasing.
#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
-attribute vec3 a_pos_normal;
+attribute vec4 a_pos_normal;
attribute vec4 a_data;
uniform mat4 u_matrix;
@@ -121,12 +121,9 @@ void main() {
vec2 pos = a_pos_normal.xy;
- // transform y normal so that 0 => -1 and 1 => 1
- // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // x is 1 if it's a round cap, 0 otherwise
// y is 1 if the normal points up, and -1 if it points down
- mediump vec2 normal = unpack_float(a_pos_normal.z);
- normal.y = sign(normal.y - 0.5);
-
+ mediump vec2 normal = a_pos_normal.zw;
v_normal = normal;
// these transformations used to be applied in the JS and native code bases.
diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp
index dd81433543..c5d50566e8 100644
--- a/src/mbgl/shaders/line_sdf.cpp
+++ b/src/mbgl/shaders/line_sdf.cpp
@@ -23,7 +23,7 @@ const char* line_sdf::vertexSource = R"MBGL_SHADER(
// Retina devices need a smaller distance to avoid aliasing.
#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
-attribute vec3 a_pos_normal;
+attribute vec4 a_pos_normal;
attribute vec4 a_data;
uniform mat4 u_matrix;
@@ -159,12 +159,9 @@ void main() {
vec2 pos = a_pos_normal.xy;
- // transform y normal so that 0 => -1 and 1 => 1
- // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // x is 1 if it's a round cap, 0 otherwise
// y is 1 if the normal points up, and -1 if it points down
- mediump vec2 normal = unpack_float(a_pos_normal.z);
- normal.y = sign(normal.y - 0.5);
-
+ mediump vec2 normal = a_pos_normal.zw;
v_normal = normal;
// these transformations used to be applied in the JS and native code bases.
diff --git a/src/mbgl/storage/resource.cpp b/src/mbgl/storage/resource.cpp
index 94bba7f8bf..207dd2ee69 100644
--- a/src/mbgl/storage/resource.cpp
+++ b/src/mbgl/storage/resource.cpp
@@ -61,17 +61,19 @@ Resource Resource::image(const std::string& url) {
}
Resource Resource::spriteImage(const std::string& base, float pixelRatio) {
- return Resource {
- Resource::Kind::SpriteImage,
- base + (pixelRatio > 1 ? "@2x" : "") + ".png"
- };
+ util::URL url(base);
+ return Resource{ Resource::Kind::SpriteImage,
+ base.substr(0, url.path.first + url.path.second) +
+ (pixelRatio > 1 ? "@2x" : "") + ".png" +
+ base.substr(url.query.first, url.query.second) };
}
Resource Resource::spriteJSON(const std::string& base, float pixelRatio) {
- return Resource {
- Resource::Kind::SpriteJSON,
- base + (pixelRatio > 1 ? "@2x" : "") + ".json"
- };
+ util::URL url(base);
+ return Resource{ Resource::Kind::SpriteJSON,
+ base.substr(0, url.path.first + url.path.second) +
+ (pixelRatio > 1 ? "@2x" : "") + ".json" +
+ base.substr(url.query.first, url.query.second) };
}
Resource Resource::glyphs(const std::string& urlTemplate, const FontStack& fontStack, const std::pair<uint16_t, uint16_t>& glyphRange) {
@@ -95,7 +97,7 @@ Resource Resource::tile(const std::string& urlTemplate,
int32_t y,
int8_t z,
Tileset::Scheme scheme,
- Necessity necessity) {
+ LoadingMethod loadingMethod) {
bool supportsRatio = urlTemplate.find("{ratio}") != std::string::npos;
if (scheme == Tileset::Scheme::TMS) {
y = (1 << z) - y - 1;
@@ -131,7 +133,7 @@ Resource Resource::tile(const std::string& urlTemplate,
y,
z
},
- necessity
+ loadingMethod
};
}
diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp
index 1a30a1f1c7..dd179f5376 100644
--- a/src/mbgl/style/function/categorical_stops.cpp
+++ b/src/mbgl/style/function/categorical_stops.cpp
@@ -34,7 +34,7 @@ template class CategoricalStops<std::array<float, 2>>;
template class CategoricalStops<std::string>;
template class CategoricalStops<TextTransformType>;
template class CategoricalStops<TextJustifyType>;
-template class CategoricalStops<TextAnchorType>;
+template class CategoricalStops<SymbolAnchorType>;
template class CategoricalStops<LineJoinType>;
} // namespace style
diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp
index 7815f4aca0..0ac6fda846 100644
--- a/src/mbgl/style/function/identity_stops.cpp
+++ b/src/mbgl/style/function/identity_stops.cpp
@@ -50,12 +50,12 @@ optional<TextJustifyType> IdentityStops<TextJustifyType>::evaluate(const Value&
}
template <>
-optional<TextAnchorType> IdentityStops<TextAnchorType>::evaluate(const Value& value) const {
+optional<SymbolAnchorType> IdentityStops<SymbolAnchorType>::evaluate(const Value& value) const {
if (!value.is<std::string>()) {
return {};
}
- return Enum<TextAnchorType>::toEnum(value.get<std::string>());
+ return Enum<SymbolAnchorType>::toEnum(value.get<std::string>());
}
template <>
diff --git a/src/mbgl/style/image_impl.hpp b/src/mbgl/style/image_impl.hpp
index 75dc83206c..e439e42695 100644
--- a/src/mbgl/style/image_impl.hpp
+++ b/src/mbgl/style/image_impl.hpp
@@ -28,5 +28,6 @@ public:
using ImageMap = std::unordered_map<std::string, Immutable<style::Image::Impl>>;
using ImageDependencies = std::set<std::string>;
+using ImageRequestPair = std::pair<ImageDependencies, uint64_t>;
} // namespace mbgl
diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp
index e37382d5ef..854c771847 100644
--- a/src/mbgl/style/layers/custom_layer.cpp
+++ b/src/mbgl/style/layers/custom_layer.cpp
@@ -8,9 +8,18 @@ namespace style {
CustomLayer::CustomLayer(const std::string& layerID,
CustomLayerInitializeFunction init,
CustomLayerRenderFunction render,
+ CustomLayerContextLostFunction contextLost,
CustomLayerDeinitializeFunction deinit,
void* context)
- : Layer(makeMutable<Impl>(layerID, init, render, deinit, context)) {
+ : Layer(makeMutable<Impl>(layerID, init, render, contextLost, deinit, context)) {
+}
+
+CustomLayer::CustomLayer(const std::string& layerID,
+ CustomLayerInitializeFunction init,
+ CustomLayerRenderFunction render,
+ CustomLayerDeinitializeFunction deinit,
+ void* context)
+ : Layer(makeMutable<Impl>(layerID, init, render, nullptr, deinit, context)) {
}
CustomLayer::~CustomLayer() = default;
diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp
index 42e60c582c..1de268d2e2 100644
--- a/src/mbgl/style/layers/custom_layer_impl.cpp
+++ b/src/mbgl/style/layers/custom_layer_impl.cpp
@@ -6,12 +6,14 @@ namespace style {
CustomLayer::Impl::Impl(const std::string& id_,
CustomLayerInitializeFunction initializeFn_,
CustomLayerRenderFunction renderFn_,
+ CustomLayerContextLostFunction contextLostFn_,
CustomLayerDeinitializeFunction deinitializeFn_,
void* context_)
: Layer::Impl(LayerType::Custom, id_, std::string()) {
initializeFn = initializeFn_;
renderFn = renderFn_;
deinitializeFn = deinitializeFn_;
+ contextLostFn = contextLostFn_;
context = context_;
}
diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp
index defbbe6894..62efbbe15b 100644
--- a/src/mbgl/style/layers/custom_layer_impl.hpp
+++ b/src/mbgl/style/layers/custom_layer_impl.hpp
@@ -14,6 +14,7 @@ public:
Impl(const std::string& id,
CustomLayerInitializeFunction,
CustomLayerRenderFunction,
+ CustomLayerContextLostFunction,
CustomLayerDeinitializeFunction,
void* context);
@@ -22,6 +23,7 @@ public:
CustomLayerInitializeFunction initializeFn = nullptr;
CustomLayerRenderFunction renderFn = nullptr;
+ CustomLayerContextLostFunction contextLostFn = nullptr;
CustomLayerDeinitializeFunction deinitializeFn = nullptr;
void* context = nullptr;
};
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index 803ae7397e..9a944657ca 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -332,6 +332,22 @@ void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> va
baseImpl = std::move(impl_);
observer->onLayerChanged(*this);
}
+DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getDefaultIconAnchor() {
+ return IconAnchor::defaultValue();
+}
+
+DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getIconAnchor() const {
+ return impl().layout.get<IconAnchor>();
+}
+
+void SymbolLayer::setIconAnchor(DataDrivenPropertyValue<SymbolAnchorType> value) {
+ if (value == getIconAnchor())
+ return;
+ auto impl_ = mutableImpl();
+ impl_->layout.get<IconAnchor>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
PropertyValue<AlignmentType> SymbolLayer::getDefaultIconPitchAlignment() {
return IconPitchAlignment::defaultValue();
}
@@ -428,15 +444,15 @@ void SymbolLayer::setTextSize(DataDrivenPropertyValue<float> value) {
baseImpl = std::move(impl_);
observer->onLayerChanged(*this);
}
-PropertyValue<float> SymbolLayer::getDefaultTextMaxWidth() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextMaxWidth() {
return TextMaxWidth::defaultValue();
}
-PropertyValue<float> SymbolLayer::getTextMaxWidth() const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextMaxWidth() const {
return impl().layout.get<TextMaxWidth>();
}
-void SymbolLayer::setTextMaxWidth(PropertyValue<float> value) {
+void SymbolLayer::setTextMaxWidth(DataDrivenPropertyValue<float> value) {
if (value == getTextMaxWidth())
return;
auto impl_ = mutableImpl();
@@ -460,15 +476,15 @@ void SymbolLayer::setTextLineHeight(PropertyValue<float> value) {
baseImpl = std::move(impl_);
observer->onLayerChanged(*this);
}
-PropertyValue<float> SymbolLayer::getDefaultTextLetterSpacing() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextLetterSpacing() {
return TextLetterSpacing::defaultValue();
}
-PropertyValue<float> SymbolLayer::getTextLetterSpacing() const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextLetterSpacing() const {
return impl().layout.get<TextLetterSpacing>();
}
-void SymbolLayer::setTextLetterSpacing(PropertyValue<float> value) {
+void SymbolLayer::setTextLetterSpacing(DataDrivenPropertyValue<float> value) {
if (value == getTextLetterSpacing())
return;
auto impl_ = mutableImpl();
@@ -492,15 +508,15 @@ void SymbolLayer::setTextJustify(DataDrivenPropertyValue<TextJustifyType> value)
baseImpl = std::move(impl_);
observer->onLayerChanged(*this);
}
-DataDrivenPropertyValue<TextAnchorType> SymbolLayer::getDefaultTextAnchor() {
+DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getDefaultTextAnchor() {
return TextAnchor::defaultValue();
}
-DataDrivenPropertyValue<TextAnchorType> SymbolLayer::getTextAnchor() const {
+DataDrivenPropertyValue<SymbolAnchorType> SymbolLayer::getTextAnchor() const {
return impl().layout.get<TextAnchor>();
}
-void SymbolLayer::setTextAnchor(DataDrivenPropertyValue<TextAnchorType> value) {
+void SymbolLayer::setTextAnchor(DataDrivenPropertyValue<SymbolAnchorType> value) {
if (value == getTextAnchor())
return;
auto impl_ = mutableImpl();
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index fe6ab38e92..436b5cbd4f 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -87,6 +87,11 @@ struct IconOffset : DataDrivenLayoutProperty<std::array<float, 2>> {
static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
};
+struct IconAnchor : DataDrivenLayoutProperty<SymbolAnchorType> {
+ static constexpr const char * key = "icon-anchor";
+ static SymbolAnchorType defaultValue() { return SymbolAnchorType::Center; }
+};
+
struct IconPitchAlignment : LayoutProperty<AlignmentType> {
static constexpr const char * key = "icon-pitch-alignment";
static AlignmentType defaultValue() { return AlignmentType::Auto; }
@@ -117,7 +122,7 @@ struct TextSize : DataDrivenLayoutProperty<float> {
static float defaultValue() { return 16; }
};
-struct TextMaxWidth : LayoutProperty<float> {
+struct TextMaxWidth : DataDrivenLayoutProperty<float> {
static constexpr const char * key = "text-max-width";
static float defaultValue() { return 10; }
};
@@ -127,7 +132,7 @@ struct TextLineHeight : LayoutProperty<float> {
static float defaultValue() { return 1.2; }
};
-struct TextLetterSpacing : LayoutProperty<float> {
+struct TextLetterSpacing : DataDrivenLayoutProperty<float> {
static constexpr const char * key = "text-letter-spacing";
static float defaultValue() { return 0; }
};
@@ -137,9 +142,9 @@ struct TextJustify : DataDrivenLayoutProperty<TextJustifyType> {
static TextJustifyType defaultValue() { return TextJustifyType::Center; }
};
-struct TextAnchor : DataDrivenLayoutProperty<TextAnchorType> {
+struct TextAnchor : DataDrivenLayoutProperty<SymbolAnchorType> {
static constexpr const char * key = "text-anchor";
- static TextAnchorType defaultValue() { return TextAnchorType::Center; }
+ static SymbolAnchorType defaultValue() { return SymbolAnchorType::Center; }
};
struct TextMaxAngle : LayoutProperty<float> {
@@ -259,6 +264,7 @@ class SymbolLayoutProperties : public Properties<
IconPadding,
IconKeepUpright,
IconOffset,
+ IconAnchor,
IconPitchAlignment,
TextPitchAlignment,
TextRotationAlignment,
diff --git a/src/mbgl/style/observer.hpp b/src/mbgl/style/observer.hpp
index ea19c599e9..cc6378b366 100644
--- a/src/mbgl/style/observer.hpp
+++ b/src/mbgl/style/observer.hpp
@@ -1,7 +1,6 @@
#pragma once
#include <mbgl/style/source_observer.hpp>
-#include <mbgl/map/update.hpp>
#include <exception>
@@ -12,7 +11,7 @@ class Observer : public SourceObserver {
public:
virtual void onStyleLoading() {}
virtual void onStyleLoaded() {}
- virtual void onUpdate(Update) {}
+ virtual void onUpdate() {}
virtual void onStyleError(std::exception_ptr) {}
virtual void onResourceError(std::exception_ptr) {}
};
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index efa4018b46..fd6d7d3013 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -71,7 +71,7 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON)
GeoJSONSource::Impl::~Impl() = default;
Range<uint8_t> GeoJSONSource::Impl::getZoomRange() const {
- return { 0, options.maxzoom };
+ return { options.minzoom, options.maxzoom };
}
GeoJSONData* GeoJSONSource::Impl::getData() const {
diff --git a/src/mbgl/style/sources/image_source.cpp b/src/mbgl/style/sources/image_source.cpp
index 9b60ba1a48..fa268da0ef 100644
--- a/src/mbgl/style/sources/image_source.cpp
+++ b/src/mbgl/style/sources/image_source.cpp
@@ -59,7 +59,7 @@ void ImageSource::loadDescription(FileSource& fileSource) {
if (req || loaded) {
return;
}
- const Resource imageResource { Resource::Image, *url, {}, Resource::Necessity::Required };
+ const Resource imageResource { Resource::Image, *url, {} };
req = fileSource.request(imageResource, [this](Response res) {
if (res.error) {
diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp
index 0fb49d1d22..37907d3f60 100644
--- a/src/mbgl/style/style_impl.cpp
+++ b/src/mbgl/style/style_impl.cpp
@@ -88,7 +88,7 @@ void Style::Impl::parse(const std::string& json_) {
}
mutated = false;
- loaded = true;
+ loaded = false;
json = json_;
sources.clear();
@@ -118,6 +118,7 @@ void Style::Impl::parse(const std::string& json_) {
spriteLoader->load(parser.spriteURL, scheduler, fileSource);
glyphURL = parser.glyphURL;
+ loaded = true;
observer->onStyleLoaded();
}
@@ -203,7 +204,7 @@ Layer* Style::Impl::addLayer(std::unique_ptr<Layer> layer, optional<std::string>
}
layer->setObserver(this);
- observer->onUpdate(Update::Repaint);
+ observer->onUpdate();
return layers.add(std::move(layer), before);
}
@@ -213,7 +214,7 @@ std::unique_ptr<Layer> Style::Impl::removeLayer(const std::string& id) {
if (layer) {
layer->setObserver(nullptr);
- observer->onUpdate(Update::Repaint);
+ observer->onUpdate();
}
return layer;
@@ -288,13 +289,13 @@ void Style::Impl::setObserver(style::Observer* observer_) {
void Style::Impl::onSourceLoaded(Source& source) {
sources.update(source);
observer->onSourceLoaded(source);
- observer->onUpdate(Update::Repaint);
+ observer->onUpdate();
}
void Style::Impl::onSourceChanged(Source& source) {
sources.update(source);
observer->onSourceChanged(source);
- observer->onUpdate(Update::Repaint);
+ observer->onUpdate();
}
void Style::Impl::onSourceError(Source& source, std::exception_ptr error) {
@@ -318,7 +319,7 @@ void Style::Impl::onSpriteLoaded(std::vector<std::unique_ptr<Image>>&& images_)
addImage(std::move(image));
}
spriteLoaded = true;
- observer->onUpdate(Update::Repaint); // For *-pattern properties.
+ observer->onUpdate(); // For *-pattern properties.
}
void Style::Impl::onSpriteError(std::exception_ptr error) {
@@ -329,11 +330,11 @@ void Style::Impl::onSpriteError(std::exception_ptr error) {
void Style::Impl::onLayerChanged(Layer& layer) {
layers.update(layer);
- observer->onUpdate(Update::Repaint);
+ observer->onUpdate();
}
void Style::Impl::onLightChanged(const Light&) {
- observer->onUpdate(Update::Repaint);
+ observer->onUpdate();
}
void Style::Impl::dumpDebugLogs() const {
diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp
index 4fbf767e11..0a1781e01b 100644
--- a/src/mbgl/style/types.cpp
+++ b/src/mbgl/style/types.cpp
@@ -53,16 +53,16 @@ MBGL_DEFINE_ENUM(SymbolPlacementType, {
{ SymbolPlacementType::Line, "line" },
});
-MBGL_DEFINE_ENUM(TextAnchorType, {
- { TextAnchorType::Center, "center" },
- { TextAnchorType::Left, "left" },
- { TextAnchorType::Right, "right" },
- { TextAnchorType::Top, "top" },
- { TextAnchorType::Bottom, "bottom" },
- { TextAnchorType::TopLeft, "top-left" },
- { TextAnchorType::TopRight, "top-right" },
- { TextAnchorType::BottomLeft, "bottom-left" },
- { TextAnchorType::BottomRight, "bottom-right" }
+MBGL_DEFINE_ENUM(SymbolAnchorType, {
+ { SymbolAnchorType::Center, "center" },
+ { SymbolAnchorType::Left, "left" },
+ { SymbolAnchorType::Right, "right" },
+ { SymbolAnchorType::Top, "top" },
+ { SymbolAnchorType::Bottom, "bottom" },
+ { SymbolAnchorType::TopLeft, "top-left" },
+ { SymbolAnchorType::TopRight, "top-right" },
+ { SymbolAnchorType::BottomLeft, "bottom-left" },
+ { SymbolAnchorType::BottomRight, "bottom-right" }
});
MBGL_DEFINE_ENUM(TextJustifyType, {
diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp
index 916d39ae62..c79a1938c1 100644
--- a/src/mbgl/text/glyph_manager.cpp
+++ b/src/mbgl/text/glyph_manager.cpp
@@ -36,8 +36,9 @@ void GlyphManager::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphD
for (const auto& range : ranges) {
auto it = entry.ranges.find(range);
if (it == entry.ranges.end() || !it->second.parsed) {
- GlyphRequest& request = requestRange(entry, fontStack, range);
+ GlyphRequest& request = entry.ranges[range];
request.requestors[&requestor] = dependencies;
+ requestRange(request, fontStack, range);
}
}
}
@@ -49,18 +50,14 @@ void GlyphManager::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphD
}
}
-GlyphManager::GlyphRequest& GlyphManager::requestRange(Entry& entry, const FontStack& fontStack, const GlyphRange& range) {
- GlyphRequest& request = entry.ranges[range];
-
+void GlyphManager::requestRange(GlyphRequest& request, const FontStack& fontStack, const GlyphRange& range) {
if (request.req) {
- return request;
+ return;
}
request.req = fileSource.request(Resource::glyphs(glyphURL, fontStack, range), [this, fontStack, range](Response res) {
processResponse(res, fontStack, range);
});
-
- return request;
}
void GlyphManager::processResponse(const Response& res, const FontStack& fontStack, const GlyphRange& range) {
diff --git a/src/mbgl/text/glyph_manager.hpp b/src/mbgl/text/glyph_manager.hpp
index 00df079462..de2b9cde7b 100644
--- a/src/mbgl/text/glyph_manager.hpp
+++ b/src/mbgl/text/glyph_manager.hpp
@@ -58,7 +58,7 @@ private:
std::unordered_map<FontStack, Entry, FontStackHash> entries;
- GlyphRequest& requestRange(Entry&, const FontStack&, const GlyphRange&);
+ void requestRange(GlyphRequest&, const FontStack&, const GlyphRange&);
void processResponse(const Response&, const FontStack&, const GlyphRange&);
void notify(GlyphRequestor&, const GlyphDependencies&);
diff --git a/src/mbgl/text/placement_config.hpp b/src/mbgl/text/placement_config.hpp
index 1e1279341d..48b24b5f41 100644
--- a/src/mbgl/text/placement_config.hpp
+++ b/src/mbgl/text/placement_config.hpp
@@ -13,9 +13,9 @@ public:
bool operator==(const PlacementConfig& rhs) const {
return angle == rhs.angle &&
pitch == rhs.pitch &&
- cameraToCenterDistance == rhs.cameraToCenterDistance &&
- (pitch * util::RAD2DEG < 25 || cameraToTileDistance == rhs.cameraToTileDistance) &&
- debug == rhs.debug;
+ debug == rhs.debug &&
+ ((pitch * util::RAD2DEG < 25) ||
+ (cameraToCenterDistance == rhs.cameraToCenterDistance && cameraToTileDistance == rhs.cameraToTileDistance));
}
bool operator!=(const PlacementConfig& rhs) const {
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index a40ef0cf39..5d688ea539 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -11,12 +11,63 @@
namespace mbgl {
-PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, const float iconRotation) {
+struct AnchorAlignment {
+ AnchorAlignment(float horizontal_, float vertical_)
+ : horizontalAlign(horizontal_), verticalAlign(vertical_) {
+ }
+
+ float horizontalAlign;
+ float verticalAlign;
+};
+
+AnchorAlignment getAnchorAlignment(style::SymbolAnchorType anchor) {
+ float horizontalAlign = 0.5;
+ float verticalAlign = 0.5;
+
+ switch (anchor) {
+ case style::SymbolAnchorType::Top:
+ case style::SymbolAnchorType::Bottom:
+ case style::SymbolAnchorType::Center:
+ break;
+ case style::SymbolAnchorType::Right:
+ case style::SymbolAnchorType::TopRight:
+ case style::SymbolAnchorType::BottomRight:
+ horizontalAlign = 1;
+ break;
+ case style::SymbolAnchorType::Left:
+ case style::SymbolAnchorType::TopLeft:
+ case style::SymbolAnchorType::BottomLeft:
+ horizontalAlign = 0;
+ break;
+ }
+
+ switch (anchor) {
+ case style::SymbolAnchorType::Left:
+ case style::SymbolAnchorType::Right:
+ case style::SymbolAnchorType::Center:
+ break;
+ case style::SymbolAnchorType::Bottom:
+ case style::SymbolAnchorType::BottomLeft:
+ case style::SymbolAnchorType::BottomRight:
+ verticalAlign = 1;
+ break;
+ case style::SymbolAnchorType::Top:
+ case style::SymbolAnchorType::TopLeft:
+ case style::SymbolAnchorType::TopRight:
+ verticalAlign = 0;
+ break;
+ }
+
+ return AnchorAlignment(horizontalAlign, verticalAlign);
+}
+
+PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, style::SymbolAnchorType iconAnchor, const float iconRotation) {
+ AnchorAlignment anchorAlign = getAnchorAlignment(iconAnchor);
float dx = iconOffset[0];
float dy = iconOffset[1];
- float x1 = dx - image.displaySize()[0] / 2.0f;
+ float x1 = dx - image.displaySize()[0] * anchorAlign.horizontalAlign;
float x2 = x1 + image.displaySize()[0];
- float y1 = dy - image.displaySize()[1] / 2.0f;
+ float y1 = dy - image.displaySize()[1] * anchorAlign.verticalAlign;
float y2 = y1 + image.displaySize()[1];
return PositionedIcon { image, y1, y2, x1, x2, iconRotation };
@@ -200,7 +251,7 @@ void shapeLines(Shaping& shaping,
const std::vector<std::u16string>& lines,
const float spacing,
const float lineHeight,
- const style::TextAnchorType textAnchor,
+ const style::SymbolAnchorType textAnchor,
const style::TextJustifyType textJustify,
const float verticalHeight,
const WritingModeType writingMode,
@@ -258,58 +309,23 @@ void shapeLines(Shaping& shaping,
y += lineHeight;
}
- float horizontalAlign = 0.5;
- float verticalAlign = 0.5;
-
- switch (textAnchor) {
- case style::TextAnchorType::Top:
- case style::TextAnchorType::Bottom:
- case style::TextAnchorType::Center:
- break;
- case style::TextAnchorType::Right:
- case style::TextAnchorType::TopRight:
- case style::TextAnchorType::BottomRight:
- horizontalAlign = 1;
- break;
- case style::TextAnchorType::Left:
- case style::TextAnchorType::TopLeft:
- case style::TextAnchorType::BottomLeft:
- horizontalAlign = 0;
- break;
- }
-
- switch (textAnchor) {
- case style::TextAnchorType::Left:
- case style::TextAnchorType::Right:
- case style::TextAnchorType::Center:
- break;
- case style::TextAnchorType::Bottom:
- case style::TextAnchorType::BottomLeft:
- case style::TextAnchorType::BottomRight:
- verticalAlign = 1;
- break;
- case style::TextAnchorType::Top:
- case style::TextAnchorType::TopLeft:
- case style::TextAnchorType::TopRight:
- verticalAlign = 0;
- break;
- }
+ auto anchorAlign = getAnchorAlignment(textAnchor);
- align(shaping, justify, horizontalAlign, verticalAlign,
- maxLineLength, lineHeight, lines.size());
+ align(shaping, justify, anchorAlign.horizontalAlign, anchorAlign.verticalAlign, maxLineLength,
+ lineHeight, lines.size());
const uint32_t height = lines.size() * lineHeight;
// Calculate the bounding box
- shaping.top += -verticalAlign * height;
+ shaping.top += -anchorAlign.verticalAlign * height;
shaping.bottom = shaping.top + height;
- shaping.left += -horizontalAlign * maxLineLength;
+ shaping.left += -anchorAlign.horizontalAlign * maxLineLength;
shaping.right = shaping.left + maxLineLength;
}
const Shaping getShaping(const std::u16string& logicalInput,
const float maxWidth,
const float lineHeight,
- const style::TextAnchorType textAnchor,
+ const style::SymbolAnchorType textAnchor,
const style::TextJustifyType textJustify,
const float spacing,
const Point<float>& translate,
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index 00e4ec55f8..0a961849e5 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -32,7 +32,10 @@ private:
float _angle;
public:
- static PositionedIcon shapeIcon(const ImagePosition&, const std::array<float, 2>& iconOffset, const float iconRotation);
+ static PositionedIcon shapeIcon(const ImagePosition&,
+ const std::array<float, 2>& iconOffset,
+ style::SymbolAnchorType iconAnchor,
+ const float iconRotation);
const ImagePosition& image() const { return _image; }
float top() const { return _top; }
@@ -45,7 +48,7 @@ public:
const Shaping getShaping(const std::u16string& string,
float maxWidth,
float lineHeight,
- style::TextAnchorType textAnchor,
+ style::SymbolAnchorType textAnchor,
style::TextJustifyType textJustify,
float spacing,
const Point<float>& translate,
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 5d8339d775..d648d2e5ff 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -1,104 +1,11 @@
#include <mbgl/tile/geojson_tile.hpp>
-#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/tile/geojson_tile_data.hpp>
#include <mbgl/renderer/query.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/util/string.hpp>
-
-#include <mapbox/geojsonvt.hpp>
-#include <supercluster.hpp>
namespace mbgl {
-// Implements a simple in-memory Tile type that holds GeoJSON values. A GeoJSON tile can only have
-// one layer, and it is always returned regardless of which layer is requested.
-
-class GeoJSONTileFeature : public GeometryTileFeature {
-public:
- const mapbox::geometry::feature<int16_t>& feature;
-
- GeoJSONTileFeature(const mapbox::geometry::feature<int16_t>& feature_)
- : feature(feature_) {
- }
-
- FeatureType getType() const override {
- return apply_visitor(ToFeatureType(), feature.geometry);
- }
-
- PropertyMap getProperties() const override {
- return feature.properties;
- }
-
- optional<FeatureIdentifier> getID() const override {
- return feature.id;
- }
-
- GeometryCollection getGeometries() const override {
- GeometryCollection geometry = apply_visitor(ToGeometryCollection(), feature.geometry);
-
- // https://github.com/mapbox/geojson-vt-cpp/issues/44
- if (getType() == FeatureType::Polygon) {
- geometry = fixupPolygons(geometry);
- }
-
- return geometry;
- }
-
- optional<Value> getValue(const std::string& key) const override {
- auto it = feature.properties.find(key);
- if (it != feature.properties.end()) {
- return optional<Value>(it->second);
- }
- return optional<Value>();
- }
-};
-
-class GeoJSONTileLayer : public GeometryTileLayer {
-public:
- GeoJSONTileLayer(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_)
- : features(std::move(features_)) {
- }
-
- std::size_t featureCount() const override {
- return features->size();
- }
-
- std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override {
- return std::make_unique<GeoJSONTileFeature>((*features)[i]);
- }
-
- std::string getName() const override {
- return "";
- }
-
-private:
- std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features;
-};
-
-class GeoJSONTileData : public GeometryTileData {
-public:
- GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_)
- : features(std::make_shared<mapbox::geometry::feature_collection<int16_t>>(
- std::move(features_))) {
- }
-
- GeoJSONTileData(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_)
- : features(std::move(features_)) {
- }
-
- std::unique_ptr<GeometryTileData> clone() const override {
- return std::make_unique<GeoJSONTileData>(features);
- }
-
- std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const override {
- return std::make_unique<GeoJSONTileLayer>(features);
- }
-
-
-private:
- std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features;
-};
-
GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
std::string sourceID_,
const TileParameters& parameters,
@@ -110,8 +17,6 @@ GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
void GeoJSONTile::updateData(mapbox::geometry::feature_collection<int16_t> features) {
setData(std::make_unique<GeoJSONTileData>(std::move(features)));
}
-
-void GeoJSONTile::setNecessity(Necessity) {}
void GeoJSONTile::querySourceFeatures(
std::vector<Feature>& result,
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index d8a0a379d7..270406267c 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -15,8 +15,6 @@ public:
mapbox::geometry::feature_collection<int16_t>);
void updateData(mapbox::geometry::feature_collection<int16_t>);
-
- void setNecessity(Necessity) final;
void querySourceFeatures(
std::vector<Feature>& result,
diff --git a/src/mbgl/tile/geojson_tile_data.hpp b/src/mbgl/tile/geojson_tile_data.hpp
new file mode 100644
index 0000000000..3402c2a009
--- /dev/null
+++ b/src/mbgl/tile/geojson_tile_data.hpp
@@ -0,0 +1,94 @@
+#include <mbgl/tile/geometry_tile_data.hpp>
+
+namespace mbgl {
+
+// Implements a simple in-memory Tile type that holds GeoJSON values. A GeoJSON tile can only have
+// one layer, and it is always returned regardless of which layer is requested.
+
+class GeoJSONTileFeature : public GeometryTileFeature {
+public:
+ const mapbox::geometry::feature<int16_t>& feature;
+
+ GeoJSONTileFeature(const mapbox::geometry::feature<int16_t>& feature_)
+ : feature(feature_) {
+ }
+
+ FeatureType getType() const override {
+ return apply_visitor(ToFeatureType(), feature.geometry);
+ }
+
+ PropertyMap getProperties() const override {
+ return feature.properties;
+ }
+
+ optional<FeatureIdentifier> getID() const override {
+ return feature.id;
+ }
+
+ GeometryCollection getGeometries() const override {
+ GeometryCollection geometry = apply_visitor(ToGeometryCollection(), feature.geometry);
+
+ // https://github.com/mapbox/geojson-vt-cpp/issues/44
+ if (getType() == FeatureType::Polygon) {
+ geometry = fixupPolygons(geometry);
+ }
+
+ return geometry;
+ }
+
+ optional<Value> getValue(const std::string& key) const override {
+ auto it = feature.properties.find(key);
+ if (it != feature.properties.end()) {
+ return optional<Value>(it->second);
+ }
+ return optional<Value>();
+ }
+};
+
+class GeoJSONTileLayer : public GeometryTileLayer {
+public:
+ GeoJSONTileLayer(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_)
+ : features(std::move(features_)) {
+ }
+
+ std::size_t featureCount() const override {
+ return features->size();
+ }
+
+ std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override {
+ return std::make_unique<GeoJSONTileFeature>((*features)[i]);
+ }
+
+ std::string getName() const override {
+ return "";
+ }
+
+private:
+ std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features;
+};
+
+class GeoJSONTileData : public GeometryTileData {
+public:
+ GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_)
+ : features(std::make_shared<mapbox::geometry::feature_collection<int16_t>>(
+ std::move(features_))) {
+ }
+
+ GeoJSONTileData(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_)
+ : features(std::move(features_)) {
+ }
+
+ std::unique_ptr<GeometryTileData> clone() const override {
+ return std::make_unique<GeoJSONTileData>(features);
+ }
+
+ std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const override {
+ return std::make_unique<GeoJSONTileLayer>(features);
+ }
+
+
+private:
+ std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 20056e355d..8c018ce3aa 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -18,7 +18,6 @@
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/util/chrono.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/actor/scheduler.hpp>
@@ -28,6 +27,22 @@ namespace mbgl {
using namespace style;
+/*
+ Correlation between GeometryTile and GeometryTileWorker is safeguarded by two
+ correlation schemes:
+
+ 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
+ still mode rendering as we want to render only when all layout and placement
+ operations are completed.
+
+ GeometryTileWorker's 'imageCorrelationID' is used for checking whether an
+ image request reply coming from `GeometryTile` is valid. Previous image
+ request replies are ignored as they result in incomplete placement attempts
+ that could flag the tile as non-pending too early.
+ */
+
GeometryTile::GeometryTile(const OverscaledTileID& id_,
std::string sourceID_,
const TileParameters& parameters)
@@ -42,8 +57,8 @@ GeometryTile::GeometryTile(const OverscaledTileID& id_,
parameters.pixelRatio),
glyphManager(parameters.glyphManager),
imageManager(parameters.imageManager),
- placementThrottler(Milliseconds(300), [this] { invokePlacement(); }),
- lastYStretch(1.0f) {
+ lastYStretch(1.0f),
+ mode(parameters.mode) {
}
GeometryTile::~GeometryTile() {
@@ -62,7 +77,6 @@ void GeometryTile::markObsolete() {
void GeometryTile::setError(std::exception_ptr err) {
loaded = true;
- renderable = false;
observer->onTileError(*this, err);
}
@@ -86,7 +100,7 @@ void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) {
++correlationID;
requestedConfig = desiredConfig;
- placementThrottler.invoke();
+ invokePlacement();
}
void GeometryTile::invokePlacement() {
@@ -120,9 +134,10 @@ void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers)
worker.invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID);
}
-void GeometryTile::onLayout(LayoutResult result) {
+void GeometryTile::onLayout(LayoutResult result, const uint64_t resultCorrelationID) {
loaded = true;
renderable = true;
+ (void)resultCorrelationID;
nonSymbolBuckets = std::move(result.nonSymbolBuckets);
featureIndex = std::move(result.featureIndex);
data = std::move(result.tileData);
@@ -130,10 +145,10 @@ void GeometryTile::onLayout(LayoutResult result) {
observer->onTileChanged(*this);
}
-void GeometryTile::onPlacement(PlacementResult result) {
+void GeometryTile::onPlacement(PlacementResult result, const uint64_t resultCorrelationID) {
loaded = true;
renderable = true;
- if (result.correlationID == correlationID) {
+ if (resultCorrelationID == correlationID) {
pending = false;
}
symbolBuckets = std::move(result.symbolBuckets);
@@ -150,10 +165,11 @@ void GeometryTile::onPlacement(PlacementResult result) {
observer->onTileChanged(*this);
}
-void GeometryTile::onError(std::exception_ptr err) {
+void GeometryTile::onError(std::exception_ptr err, const uint64_t resultCorrelationID) {
loaded = true;
- pending = false;
- renderable = false;
+ if (resultCorrelationID == correlationID) {
+ pending = false;
+ }
observer->onTileError(*this, err);
}
@@ -165,12 +181,12 @@ void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) {
glyphManager.getGlyphs(*this, std::move(glyphDependencies));
}
-void GeometryTile::onImagesAvailable(ImageMap images) {
- worker.invoke(&GeometryTileWorker::onImagesAvailable, std::move(images));
+void GeometryTile::onImagesAvailable(ImageMap images, uint64_t imageCorrelationID) {
+ worker.invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), imageCorrelationID);
}
-void GeometryTile::getImages(ImageDependencies imageDependencies) {
- imageManager.getImages(*this, std::move(imageDependencies));
+void GeometryTile::getImages(ImageRequestPair pair) {
+ imageManager.getImages(*this, std::move(pair));
}
void GeometryTile::upload(gl::Context& context) {
@@ -214,11 +230,20 @@ void GeometryTile::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState& transformState,
- const RenderStyle& style,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) {
if (!featureIndex || !data) return;
+ // Determine the additional radius needed factoring in property functions
+ float additionalRadius = 0;
+ for (const RenderLayer* layer : layers) {
+ auto bucket = getBucket(*layer->baseImpl);
+ if (bucket) {
+ additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(*layer));
+ }
+ }
+
featureIndex->query(result,
queryGeometry,
transformState.getAngle(),
@@ -227,9 +252,9 @@ void GeometryTile::queryRenderedFeatures(
options,
*data,
id.canonical,
- style,
+ layers,
collisionTile.get(),
- *this);
+ additionalRadius);
}
void GeometryTile::querySourceFeatures(
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index c45762742b..a478aad504 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -19,7 +19,6 @@
namespace mbgl {
class GeometryTileData;
-class RenderStyle;
class RenderLayer;
class SourceQueryOptions;
class TileParameters;
@@ -41,10 +40,10 @@ public:
void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) override;
void onGlyphsAvailable(GlyphMap) override;
- void onImagesAvailable(ImageMap) override;
+ void onImagesAvailable(ImageMap, uint64_t imageCorrelationID) override;
void getGlyphs(GlyphDependencies);
- void getImages(ImageDependencies);
+ void getImages(ImageRequestPair);
void upload(gl::Context&) override;
Bucket* getBucket(const style::Layer::Impl&) const override;
@@ -56,7 +55,7 @@ public:
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState&,
- const RenderStyle&,
+ const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options) override;
void querySourceFeatures(
@@ -70,18 +69,15 @@ public:
std::unordered_map<std::string, std::shared_ptr<Bucket>> nonSymbolBuckets;
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<GeometryTileData> tileData;
- uint64_t correlationID;
LayoutResult(std::unordered_map<std::string, std::shared_ptr<Bucket>> nonSymbolBuckets_,
std::unique_ptr<FeatureIndex> featureIndex_,
- std::unique_ptr<GeometryTileData> tileData_,
- uint64_t correlationID_)
+ std::unique_ptr<GeometryTileData> tileData_)
: nonSymbolBuckets(std::move(nonSymbolBuckets_)),
featureIndex(std::move(featureIndex_)),
- tileData(std::move(tileData_)),
- correlationID(correlationID_) {}
+ tileData(std::move(tileData_)) {}
};
- void onLayout(LayoutResult);
+ void onLayout(LayoutResult, uint64_t correlationID);
class PlacementResult {
public:
@@ -89,22 +85,19 @@ public:
std::unique_ptr<CollisionTile> collisionTile;
optional<AlphaImage> glyphAtlasImage;
optional<PremultipliedImage> iconAtlasImage;
- uint64_t correlationID;
PlacementResult(std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets_,
std::unique_ptr<CollisionTile> collisionTile_,
optional<AlphaImage> glyphAtlasImage_,
- optional<PremultipliedImage> iconAtlasImage_,
- uint64_t correlationID_)
+ optional<PremultipliedImage> iconAtlasImage_)
: symbolBuckets(std::move(symbolBuckets_)),
collisionTile(std::move(collisionTile_)),
glyphAtlasImage(std::move(glyphAtlasImage_)),
- iconAtlasImage(std::move(iconAtlasImage_)),
- correlationID(correlationID_) {}
+ iconAtlasImage(std::move(iconAtlasImage_)) {}
};
- void onPlacement(PlacementResult);
+ void onPlacement(PlacementResult, uint64_t correlationID);
- void onError(std::exception_ptr);
+ void onError(std::exception_ptr, uint64_t correlationID);
float yStretch() const override;
@@ -140,9 +133,9 @@ private:
std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets;
std::unique_ptr<CollisionTile> collisionTile;
-
- util::Throttler placementThrottler;
+
float lastYStretch;
+ const MapMode mode;
public:
optional<gl::Texture> glyphAtlasTexture;
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index add1ea343c..50429420c3 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -88,7 +88,7 @@ void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_,
break;
}
} catch (...) {
- parent.invoke(&GeometryTile::onError, std::current_exception());
+ parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}
@@ -112,7 +112,7 @@ void GeometryTileWorker::setLayers(std::vector<Immutable<Layer::Impl>> layers_,
break;
}
} catch (...) {
- parent.invoke(&GeometryTile::onError, std::current_exception());
+ parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}
@@ -136,7 +136,7 @@ void GeometryTileWorker::setPlacementConfig(PlacementConfig placementConfig_, ui
break;
}
} catch (...) {
- parent.invoke(&GeometryTile::onError, std::current_exception());
+ parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}
@@ -161,7 +161,7 @@ void GeometryTileWorker::symbolDependenciesChanged() {
break;
}
} catch (...) {
- parent.invoke(&GeometryTile::onError, std::current_exception());
+ parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}
@@ -187,7 +187,7 @@ void GeometryTileWorker::coalesced() {
break;
}
} catch (...) {
- parent.invoke(&GeometryTile::onError, std::current_exception());
+ parent.invoke(&GeometryTile::onError, std::current_exception(), correlationID);
}
}
@@ -216,14 +216,12 @@ void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) {
symbolDependenciesChanged();
}
-void GeometryTileWorker::onImagesAvailable(ImageMap newImageMap) {
- imageMap = std::move(newImageMap);
- for (const auto& pair : imageMap) {
- auto it = pendingImageDependencies.find(pair.first);
- if (it != pendingImageDependencies.end()) {
- pendingImageDependencies.erase(it);
- }
+void GeometryTileWorker::onImagesAvailable(ImageMap newImageMap, uint64_t imageCorrelationID_) {
+ if (imageCorrelationID != imageCorrelationID_) {
+ return; // Ignore outdated image request replies.
}
+ imageMap = std::move(newImageMap);
+ pendingImageDependencies.clear();
symbolDependenciesChanged();
}
@@ -244,7 +242,7 @@ void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependen
void GeometryTileWorker::requestNewImages(const ImageDependencies& imageDependencies) {
pendingImageDependencies = imageDependencies;
if (!pendingImageDependencies.empty()) {
- parent.invoke(&GeometryTile::getImages, pendingImageDependencies);
+ parent.invoke(&GeometryTile::getImages, std::make_pair(pendingImageDependencies, ++imageCorrelationID));
}
}
@@ -359,8 +357,7 @@ void GeometryTileWorker::redoLayout() {
std::move(buckets),
std::move(featureIndex),
*data ? (*data)->clone() : nullptr,
- correlationID
- });
+ }, correlationID);
attemptPlacement();
}
@@ -424,8 +421,7 @@ void GeometryTileWorker::attemptPlacement() {
std::move(collisionTile),
std::move(glyphAtlasImage),
std::move(iconAtlasImage),
- correlationID
- });
+ }, correlationID);
}
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp
index 7f80c3b4f7..1425daa7a1 100644
--- a/src/mbgl/tile/geometry_tile_worker.hpp
+++ b/src/mbgl/tile/geometry_tile_worker.hpp
@@ -38,7 +38,7 @@ public:
void setPlacementConfig(PlacementConfig, uint64_t correlationID);
void onGlyphsAvailable(GlyphMap glyphs);
- void onImagesAvailable(ImageMap images);
+ void onImagesAvailable(ImageMap images, uint64_t imageCorrelationID);
private:
void coalesced();
@@ -70,6 +70,7 @@ private:
State state = Idle;
uint64_t correlationID = 0;
+ uint64_t imageCorrelationID = 0;
// Outer optional indicates whether we've received it or not.
optional<std::vector<Immutable<style::Layer::Impl>>> layers;
diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp
index b940e342d7..85fcea77b7 100644
--- a/src/mbgl/tile/raster_tile.cpp
+++ b/src/mbgl/tile/raster_tile.cpp
@@ -29,29 +29,35 @@ void RasterTile::cancel() {
void RasterTile::setError(std::exception_ptr err) {
loaded = true;
- renderable = false;
observer->onTileError(*this, err);
}
-void RasterTile::setData(std::shared_ptr<const std::string> data,
- optional<Timestamp> modified_,
- optional<Timestamp> expires_) {
+void RasterTile::setMetadata(optional<Timestamp> modified_, optional<Timestamp> expires_) {
modified = modified_;
expires = expires_;
- worker.invoke(&RasterTileWorker::parse, data);
}
-void RasterTile::onParsed(std::unique_ptr<RasterBucket> result) {
+void RasterTile::setData(std::shared_ptr<const std::string> data) {
+ pending = true;
+ ++correlationID;
+ worker.invoke(&RasterTileWorker::parse, data, correlationID);
+}
+
+void RasterTile::onParsed(std::unique_ptr<RasterBucket> result, const uint64_t resultCorrelationID) {
bucket = std::move(result);
loaded = true;
+ if (resultCorrelationID == correlationID) {
+ pending = false;
+ }
renderable = bucket ? true : false;
observer->onTileChanged(*this);
}
-void RasterTile::onError(std::exception_ptr err) {
- bucket.reset();
+void RasterTile::onError(std::exception_ptr err, const uint64_t resultCorrelationID) {
loaded = true;
- renderable = false;
+ if (resultCorrelationID == correlationID) {
+ pending = false;
+ }
observer->onTileError(*this, err);
}
@@ -71,7 +77,7 @@ void RasterTile::setMask(TileMask&& mask) {
}
}
-void RasterTile::setNecessity(Necessity necessity) {
+void RasterTile::setNecessity(TileNecessity necessity) {
loader.setNecessity(necessity);
}
diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp
index 28a27b2b37..192769ed8f 100644
--- a/src/mbgl/tile/raster_tile.hpp
+++ b/src/mbgl/tile/raster_tile.hpp
@@ -22,12 +22,11 @@ public:
const Tileset&);
~RasterTile() final;
- void setNecessity(Necessity) final;
+ void setNecessity(TileNecessity) final;
void setError(std::exception_ptr);
- void setData(std::shared_ptr<const std::string> data,
- optional<Timestamp> modified_,
- optional<Timestamp> expires_);
+ void setMetadata(optional<Timestamp> modified, optional<Timestamp> expires);
+ void setData(std::shared_ptr<const std::string> data);
void cancel() override;
@@ -36,8 +35,8 @@ public:
void setMask(TileMask&&) override;
- void onParsed(std::unique_ptr<RasterBucket> result);
- void onError(std::exception_ptr);
+ void onParsed(std::unique_ptr<RasterBucket> result, uint64_t correlationID);
+ void onError(std::exception_ptr, uint64_t correlationID);
private:
TileLoader<RasterTile> loader;
@@ -45,6 +44,8 @@ private:
std::shared_ptr<Mailbox> mailbox;
Actor<RasterTileWorker> worker;
+ uint64_t correlationID = 0;
+
// Contains the Bucket object for the tile. Buckets are render
// objects and they get added by tile parsing operations.
std::unique_ptr<RasterBucket> bucket;
diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp
index 3c8af97b40..4afa876429 100644
--- a/src/mbgl/tile/raster_tile_worker.cpp
+++ b/src/mbgl/tile/raster_tile_worker.cpp
@@ -10,17 +10,17 @@ RasterTileWorker::RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTi
: parent(std::move(parent_)) {
}
-void RasterTileWorker::parse(std::shared_ptr<const std::string> data) {
+void RasterTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID) {
if (!data) {
- parent.invoke(&RasterTile::onParsed, nullptr); // No data; empty tile.
+ parent.invoke(&RasterTile::onParsed, nullptr, correlationID); // No data; empty tile.
return;
}
try {
auto bucket = std::make_unique<RasterBucket>(decodeImage(*data));
- parent.invoke(&RasterTile::onParsed, std::move(bucket));
+ parent.invoke(&RasterTile::onParsed, std::move(bucket), correlationID);
} catch (...) {
- parent.invoke(&RasterTile::onError, std::current_exception());
+ parent.invoke(&RasterTile::onError, std::current_exception(), correlationID);
}
}
diff --git a/src/mbgl/tile/raster_tile_worker.hpp b/src/mbgl/tile/raster_tile_worker.hpp
index 44bc37ca5d..520973c3c3 100644
--- a/src/mbgl/tile/raster_tile_worker.hpp
+++ b/src/mbgl/tile/raster_tile_worker.hpp
@@ -13,7 +13,7 @@ class RasterTileWorker {
public:
RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTile>);
- void parse(std::shared_ptr<const std::string> data);
+ void parse(std::shared_ptr<const std::string> data, uint64_t correlationID);
private:
ActorRef<RasterTile> parent;
diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp
index 35fc31dae1..f36a472e72 100644
--- a/src/mbgl/tile/tile.cpp
+++ b/src/mbgl/tile/tile.cpp
@@ -18,7 +18,7 @@ void Tile::setObserver(TileObserver* observer_) {
observer = observer_;
}
-void Tile::setTriedOptional() {
+void Tile::setTriedCache() {
triedOptional = true;
observer->onTileChanged(*this);
}
@@ -33,7 +33,7 @@ void Tile::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>&,
const GeometryCoordinates&,
const TransformState&,
- const RenderStyle&,
+ const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&) {}
void Tile::querySourceFeatures(
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index a1ab6a84b7..8be7c4d862 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -6,6 +6,7 @@
#include <mbgl/util/feature.hpp>
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/tile/tile_necessity.hpp>
#include <mbgl/renderer/tile_mask.hpp>
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
@@ -23,7 +24,7 @@ class DebugBucket;
class TransformState;
class TileObserver;
class PlacementConfig;
-class RenderStyle;
+class RenderLayer;
class RenderedQueryOptions;
class SourceQueryOptions;
@@ -38,14 +39,7 @@ public:
void setObserver(TileObserver* observer);
- // Tiles can have two states: optional or required.
- // - optional means that only low-cost actions should be taken to obtain the data
- // (e.g. load from cache, but accept stale data)
- // - required means that every effort should be taken to obtain the data (e.g. load
- // from internet and keep the data fresh if it expires)
- using Necessity = Resource::Necessity;
-
- virtual void setNecessity(Necessity) = 0;
+ virtual void setNecessity(TileNecessity) {}
// Mark this tile as no longer needed and cancel any pending work.
virtual void cancel() = 0;
@@ -61,18 +55,18 @@ public:
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState&,
- const RenderStyle&,
+ const std::vector<const RenderLayer*>&,
const RenderedQueryOptions& options);
virtual void querySourceFeatures(
std::vector<Feature>& result,
const SourceQueryOptions&);
- void setTriedOptional();
+ void setTriedCache();
// Returns true when the tile source has received a first response, regardless of whether a load
// error occurred or actual data was loaded.
- bool hasTriedOptional() const {
+ bool hasTriedCache() const {
return triedOptional;
}
diff --git a/src/mbgl/tile/tile_id_hash.cpp b/src/mbgl/tile/tile_id_hash.cpp
new file mode 100644
index 0000000000..4a1f185817
--- /dev/null
+++ b/src/mbgl/tile/tile_id_hash.cpp
@@ -0,0 +1,29 @@
+#include <mbgl/tile/tile_id.hpp>
+
+#include <boost/functional/hash.hpp>
+
+namespace std {
+
+size_t hash<mbgl::CanonicalTileID>::operator()(const mbgl::CanonicalTileID& id) const {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, id.x);
+ boost::hash_combine(seed, id.y);
+ boost::hash_combine(seed, id.z);
+ return seed;
+}
+
+size_t hash<mbgl::UnwrappedTileID>::operator()(const mbgl::UnwrappedTileID& id) const {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical));
+ boost::hash_combine(seed, id.wrap);
+ return seed;
+}
+
+size_t hash<mbgl::OverscaledTileID>::operator()(const mbgl::OverscaledTileID& id) const {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, std::hash<mbgl::CanonicalTileID>{}(id.canonical));
+ boost::hash_combine(seed, id.overscaledZ);
+ return seed;
+}
+
+} // namespace std
diff --git a/src/mbgl/tile/tile_loader.hpp b/src/mbgl/tile/tile_loader.hpp
index bc408ebaf6..92ca74330f 100644
--- a/src/mbgl/tile/tile_loader.hpp
+++ b/src/mbgl/tile/tile_loader.hpp
@@ -21,12 +21,10 @@ public:
const Tileset&);
~TileLoader();
- using Necessity = Resource::Necessity;
-
- void setNecessity(Necessity newNecessity) {
+ void setNecessity(TileNecessity newNecessity) {
if (newNecessity != necessity) {
necessity = newNecessity;
- if (necessity == Necessity::Required) {
+ if (necessity == TileNecessity::Required) {
makeRequired();
} else {
makeOptional();
@@ -45,12 +43,12 @@ private:
// an up-to-date version or load new data
void makeOptional();
- void loadOptional();
+ void loadFromCache();
void loadedData(const Response&);
- void loadRequired();
+ void loadFromNetwork();
T& tile;
- Necessity necessity;
+ TileNecessity necessity;
Resource resource;
FileSource& fileSource;
std::unique_ptr<AsyncRequest> request;
diff --git a/src/mbgl/tile/tile_loader_impl.hpp b/src/mbgl/tile/tile_loader_impl.hpp
index 899cbaf9b0..1b29638269 100644
--- a/src/mbgl/tile/tile_loader_impl.hpp
+++ b/src/mbgl/tile/tile_loader_impl.hpp
@@ -15,32 +15,31 @@ TileLoader<T>::TileLoader(T& tile_,
const TileParameters& parameters,
const Tileset& tileset)
: tile(tile_),
- necessity(Necessity::Optional),
+ necessity(TileNecessity::Optional),
resource(Resource::tile(
tileset.tiles.at(0),
parameters.pixelRatio,
id.canonical.x,
id.canonical.y,
id.canonical.z,
- tileset.scheme)),
+ tileset.scheme,
+ Resource::LoadingMethod::CacheOnly)),
fileSource(parameters.fileSource) {
assert(!request);
- if (fileSource.supportsOptionalRequests()) {
+ if (fileSource.supportsCacheOnlyRequests()) {
// When supported, the first request is always optional, even if the TileLoader
// is marked as required. That way, we can let the first optional request continue
// to load when the TileLoader is later changed from required to optional. If we
// started out with a required request, we'd have to cancel everything, including the
// initial optional part of the request.
- loadOptional();
+ loadFromCache();
+ } else if (necessity == TileNecessity::Required) {
+ // When the file source doesn't support cache-only requests, and we definiitely need this
+ // data, we can start out with a network request immediately.
+ loadFromNetwork();
} else {
- // When the FileSource doesn't support optional requests, we do nothing until the
+ // When the FileSource doesn't support cache-only requests, we do nothing until the
// data is definitely required.
- if (necessity == Necessity::Required) {
- loadRequired();
- } else {
- // We're using this field to check whether the pending request is optional or required.
- resource.necessity = Resource::Optional;
- }
}
}
@@ -48,26 +47,31 @@ template <typename T>
TileLoader<T>::~TileLoader() = default;
template <typename T>
-void TileLoader<T>::loadOptional() {
+void TileLoader<T>::loadFromCache() {
assert(!request);
- resource.necessity = Resource::Optional;
+ resource.loadingMethod = Resource::LoadingMethod::CacheOnly;
request = fileSource.request(resource, [this](Response res) {
request.reset();
- tile.setTriedOptional();
+ tile.setTriedCache();
if (res.error && res.error->reason == Response::Error::Reason::NotFound) {
- // When the optional request could not be satisfied, don't treat it as an error.
- // Instead, we make sure that the next request knows that there has been an optional
- // request before by setting one of the prior* fields.
- resource.priorExpires = Timestamp{ Seconds::zero() };
+ // When the cache-only request could not be satisfied, don't treat it as an error.
+ // A cache lookup could still return data, _and_ an error, in particular when we were
+ // able to find the data, but it is expired and the Cache-Control headers indicated that
+ // we aren't allowed to use expired responses. In this case, we still get the data which
+ // we can use in our conditional network request.
+ resource.priorModified = res.modified;
+ resource.priorExpires = res.expires;
+ resource.priorEtag = res.etag;
+ resource.priorData = res.data;
} else {
loadedData(res);
}
- if (necessity == Necessity::Required) {
- loadRequired();
+ if (necessity == TileNecessity::Required) {
+ loadFromNetwork();
}
});
}
@@ -75,14 +79,15 @@ void TileLoader<T>::loadOptional() {
template <typename T>
void TileLoader<T>::makeRequired() {
if (!request) {
- loadRequired();
+ loadFromNetwork();
}
}
template <typename T>
void TileLoader<T>::makeOptional() {
- if (resource.necessity == Resource::Required && request) {
- // Abort a potential HTTP request.
+ if (resource.loadingMethod == Resource::LoadingMethod::NetworkOnly && request) {
+ // Abort the current request, but only when we know that we're specifically querying for a
+ // network resource only.
request.reset();
}
}
@@ -95,19 +100,23 @@ void TileLoader<T>::loadedData(const Response& res) {
resource.priorExpires = res.expires;
// Do not notify the tile; when we get this message, it already has the current
// version of the data.
+ tile.setMetadata(res.modified, res.expires);
} else {
resource.priorModified = res.modified;
resource.priorExpires = res.expires;
resource.priorEtag = res.etag;
- tile.setData(res.noContent ? nullptr : res.data, res.modified, res.expires);
+ tile.setMetadata(res.modified, res.expires);
+ tile.setData(res.noContent ? nullptr : res.data);
}
}
template <typename T>
-void TileLoader<T>::loadRequired() {
+void TileLoader<T>::loadFromNetwork() {
assert(!request);
- resource.necessity = Resource::Required;
+ // Instead of using Resource::LoadingMethod::All, we're first doing a CacheOnly, and then a
+ // NetworkOnly request.
+ resource.loadingMethod = Resource::LoadingMethod::NetworkOnly;
request = fileSource.request(resource, [this](Response res) { loadedData(res); });
}
diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index e2e700b7b7..0756d3e526 100644
--- a/src/mbgl/tile/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -12,16 +12,16 @@ VectorTile::VectorTile(const OverscaledTileID& id_,
: GeometryTile(id_, sourceID_, parameters), loader(*this, id_, parameters, tileset) {
}
-void VectorTile::setNecessity(Necessity necessity) {
+void VectorTile::setNecessity(TileNecessity necessity) {
loader.setNecessity(necessity);
}
-void VectorTile::setData(std::shared_ptr<const std::string> data_,
- optional<Timestamp> modified_,
- optional<Timestamp> expires_) {
+void VectorTile::setMetadata(optional<Timestamp> modified_, optional<Timestamp> expires_) {
modified = modified_;
expires = expires_;
+}
+void VectorTile::setData(std::shared_ptr<const std::string> data_) {
GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr);
}
diff --git a/src/mbgl/tile/vector_tile.hpp b/src/mbgl/tile/vector_tile.hpp
index 566cde4f37..7dae414fef 100644
--- a/src/mbgl/tile/vector_tile.hpp
+++ b/src/mbgl/tile/vector_tile.hpp
@@ -15,10 +15,9 @@ public:
const TileParameters&,
const Tileset&);
- void setNecessity(Necessity) final;
- void setData(std::shared_ptr<const std::string> data,
- optional<Timestamp> modified,
- optional<Timestamp> expires);
+ void setNecessity(TileNecessity) final;
+ void setMetadata(optional<Timestamp> modified, optional<Timestamp> expires);
+ void setData(std::shared_ptr<const std::string> data);
private:
TileLoader<VectorTile> loader;
diff --git a/src/mbgl/util/constants.cpp b/src/mbgl/util/constants.cpp
index 9faef140ef..56f78c9885 100644
--- a/src/mbgl/util/constants.cpp
+++ b/src/mbgl/util/constants.cpp
@@ -11,7 +11,6 @@ const bool tileParseWarnings = false;
const bool styleParseWarnings = false;
const bool spriteWarnings = false;
const bool renderWarnings = false;
-const bool renderTree = false;
const bool labelTextMissingWarning = true;
const bool missingFontStackWarning = true;
const bool missingFontFaceWarning = true;
@@ -22,7 +21,6 @@ const bool tileParseWarnings = false;
const bool styleParseWarnings = false;
const bool spriteWarnings = false;
const bool renderWarnings = false;
-const bool renderTree = false;
const bool labelTextMissingWarning = false;
const bool missingFontStackWarning = false;
const bool missingFontFaceWarning = false;
diff --git a/src/mbgl/util/http_timeout.cpp b/src/mbgl/util/http_timeout.cpp
index ca9a93498f..3456369250 100644
--- a/src/mbgl/util/http_timeout.cpp
+++ b/src/mbgl/util/http_timeout.cpp
@@ -1,6 +1,8 @@
#include <mbgl/util/http_timeout.hpp>
#include <mbgl/util/constants.hpp>
+#include <cassert>
+
namespace mbgl {
namespace http {
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 16f1d669f3..3e3a68e248 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -554,7 +554,7 @@ std::u16string verticalizePunctuation(const std::u16string& input) {
std::u16string output;
for (size_t i = 0; i < input.size(); i++) {
- char16_t nextCharCode = i < input.size() ? input[i + 1] : 0;
+ char16_t nextCharCode = i < input.size() - 1 ? input[i + 1] : 0;
char16_t prevCharCode = i ? input[i - 1] : 0;
bool canReplacePunctuation =
diff --git a/src/mbgl/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp
index 8cbc85d492..802b527a26 100644
--- a/src/mbgl/util/mapbox.cpp
+++ b/src/mbgl/util/mapbox.cpp
@@ -114,7 +114,7 @@ std::string normalizeTileURL(const std::string& baseURL,
}
std::string
-canonicalizeTileURL(const std::string& str, const SourceType type, const uint16_t tileSize) {
+canonicalizeTileURL(const std::string& str, const style::SourceType type, const uint16_t tileSize) {
const char* version = "/v4/";
const size_t versionLen = strlen(version);
@@ -133,7 +133,7 @@ canonicalizeTileURL(const std::string& str, const SourceType type, const uint16_
std::string result = "mapbox://tiles/";
result.append(str, path.directory.first + versionLen, path.directory.second - versionLen);
result.append(str, path.filename.first, path.filename.second);
- if (type == SourceType::Raster) {
+ if (type == style::SourceType::Raster) {
result += tileSize == util::tileSize ? "@2x" : "{ratio}";
}
@@ -171,7 +171,7 @@ canonicalizeTileURL(const std::string& str, const SourceType type, const uint16_
return result;
}
-void canonicalizeTileset(Tileset& tileset, const std::string& sourceURL, SourceType type, uint16_t tileSize) {
+void canonicalizeTileset(Tileset& tileset, const std::string& sourceURL, style::SourceType type, uint16_t tileSize) {
// TODO: Remove this hack by delivering proper URLs in the TileJSON to begin with.
if (isMapboxURL(sourceURL)) {
for (auto& url : tileset.tiles) {
diff --git a/src/mbgl/util/mapbox.hpp b/src/mbgl/util/mapbox.hpp
index f3dfdd0b01..aa128f2667 100644
--- a/src/mbgl/util/mapbox.hpp
+++ b/src/mbgl/util/mapbox.hpp
@@ -19,10 +19,10 @@ std::string normalizeGlyphsURL(const std::string& baseURL, const std::string& ur
std::string normalizeTileURL(const std::string& baseURL, const std::string& url, const std::string& accessToken);
// Return a "mapbox://tiles/..." URL (suitable for normalizeTileURL) for the given Mapbox tile URL.
-std::string canonicalizeTileURL(const std::string& url, SourceType, uint16_t tileSize);
+std::string canonicalizeTileURL(const std::string& url, style::SourceType, uint16_t tileSize);
// Replace URL templates with "mapbox://tiles/..." URLs (suitable for normalizeTileURL).
-void canonicalizeTileset(Tileset&, const std::string& url, SourceType, uint16_t tileSize);
+void canonicalizeTileset(Tileset&, const std::string& url, style::SourceType, uint16_t tileSize);
extern const uint64_t DEFAULT_OFFLINE_TILE_COUNT_LIMIT;
diff --git a/src/mbgl/util/math.hpp b/src/mbgl/util/math.hpp
index fcde01c1a3..c18ce0c254 100644
--- a/src/mbgl/util/math.hpp
+++ b/src/mbgl/util/math.hpp
@@ -77,9 +77,9 @@ T mag(const S& a) {
return std::sqrt(a.x * a.x + a.y * a.y);
}
-template <typename S>
+template <typename T = double, typename S>
S unit(const S& a) {
- auto magnitude = mag(a);
+ auto magnitude = mag<T>(a);
if (magnitude == 0) {
return a;
}
diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp
index 77a1416e48..339e74b250 100644
--- a/src/mbgl/util/offscreen_texture.cpp
+++ b/src/mbgl/util/offscreen_texture.cpp
@@ -11,20 +11,22 @@ OffscreenTexture& OffscreenTexture::operator=(OffscreenTexture&&) = default;
class OffscreenTexture::Impl {
public:
- Impl(gl::Context& context_, const Size size_, OffscreenTextureAttachment type_)
- : context(context_), size(std::move(size_)), type(type_) {
+ Impl(gl::Context& context_, const Size size_)
+ : context(context_), size(std::move(size_)) {
+ assert(!size.isEmpty());
+ }
+ Impl(gl::Context& context_,
+ const Size size_,
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& depth_)
+ : context(context_), size(std::move(size_)), depth(&depth_) {
assert(!size.isEmpty());
}
void bind() {
if (!framebuffer) {
texture = context.createTexture(size, gl::TextureFormat::RGBA);
-
- if (type == OffscreenTextureAttachment::Depth) {
- gl::Renderbuffer<gl::RenderbufferType::DepthComponent> depth =
- context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(size);
- framebuffer = context.createFramebuffer(*texture, depth);
-
+ if (depth) {
+ framebuffer = context.createFramebuffer(*texture, *depth);
} else {
framebuffer = context.createFramebuffer(*texture);
}
@@ -32,7 +34,7 @@ public:
context.bindFramebuffer = framebuffer->framebuffer;
}
- context.activeTexture = 0;
+ context.activeTextureUnit = 0;
context.scissorTest = false;
context.viewport = { 0, 0, size };
}
@@ -53,15 +55,21 @@ public:
private:
gl::Context& context;
const Size size;
- OffscreenTextureAttachment type;
optional<gl::Framebuffer> framebuffer;
optional<gl::Texture> texture;
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>* depth = nullptr;
};
OffscreenTexture::OffscreenTexture(gl::Context& context,
+ const Size size)
+ : impl(std::make_unique<Impl>(context, std::move(size))) {
+ assert(!size.isEmpty());
+}
+
+OffscreenTexture::OffscreenTexture(gl::Context& context,
const Size size,
- OffscreenTextureAttachment type)
- : impl(std::make_unique<Impl>(context, std::move(size), type)) {
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& renderbuffer)
+ : impl(std::make_unique<Impl>(context, std::move(size), renderbuffer)) {
assert(!size.isEmpty());
}
diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp
index 0353f3f9c5..7f7e0f0338 100644
--- a/src/mbgl/util/offscreen_texture.hpp
+++ b/src/mbgl/util/offscreen_texture.hpp
@@ -9,16 +9,13 @@ class Context;
class Texture;
} // namespace gl
-enum class OffscreenTextureAttachment {
- None,
- Depth,
-};
-
class OffscreenTexture {
public:
OffscreenTexture(gl::Context&,
- Size size = { 256, 256 },
- OffscreenTextureAttachment type = OffscreenTextureAttachment::None);
+ Size size = { 256, 256 });
+ OffscreenTexture(gl::Context&,
+ Size size,
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>&);
~OffscreenTexture();
OffscreenTexture(OffscreenTexture&&);
OffscreenTexture& operator=(OffscreenTexture&&);
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index b53e91162c..c81becb986 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -126,9 +126,9 @@ std::vector<UnwrappedTileID> tileCover(const Point<double>& tl,
} // namespace
-int32_t coveringZoomLevel(double zoom, SourceType type, uint16_t size) {
+int32_t coveringZoomLevel(double zoom, style::SourceType type, uint16_t size) {
zoom += std::log(util::tileSize / size) / std::log(2);
- if (type == SourceType::Raster || type == SourceType::Video) {
+ if (type == style::SourceType::Raster || type == style::SourceType::Video) {
return ::round(zoom);
} else {
return std::floor(zoom);
@@ -169,5 +169,26 @@ std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
z);
}
+// Taken from https://github.com/mapbox/sphericalmercator#xyzbbox-zoom-tms_style-srs
+// Computes the projected tiles for the lower left and upper right points of the bounds
+// and uses that to compute the tile cover count
+uint64_t tileCount(const LatLngBounds& bounds, uint8_t zoom, uint16_t tileSize_){
+
+ auto sw = Projection::project(bounds.southwest().wrapped(), zoom, tileSize_);
+ auto ne = Projection::project(bounds.northeast().wrapped(), zoom, tileSize_);
+
+ auto x1 = floor(sw.x/ tileSize_);
+ auto x2 = floor((ne.x - 1) / tileSize_);
+ auto y1 = floor(sw.y/ tileSize_);
+ auto y2 = floor((ne.y - 1) / tileSize_);
+
+ auto minX = std::fmax(std::min(x1, x2), 0);
+ auto maxX = std::max(x1, x2);
+ auto minY = (std::pow(2, zoom) - 1) - std::max(y1, y2);
+ auto maxY = (std::pow(2, zoom) - 1) - std::fmax(std::min(y1, y2), 0);
+
+ return (maxX - minX + 1) * (maxY - minY + 1);
+}
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover.hpp b/src/mbgl/util/tile_cover.hpp
index 2d32d8bf41..b2098b59b8 100644
--- a/src/mbgl/util/tile_cover.hpp
+++ b/src/mbgl/util/tile_cover.hpp
@@ -13,10 +13,13 @@ class LatLngBounds;
namespace util {
-int32_t coveringZoomLevel(double z, SourceType type, uint16_t tileSize);
+int32_t coveringZoomLevel(double z, style::SourceType type, uint16_t tileSize);
std::vector<UnwrappedTileID> tileCover(const TransformState&, int32_t z);
std::vector<UnwrappedTileID> tileCover(const LatLngBounds&, int32_t z);
+// Compute only the count of tiles needed for tileCover
+uint64_t tileCount(const LatLngBounds&, uint8_t z, uint16_t tileSize);
+
} // namespace util
} // namespace mbgl