diff options
author | Thiago Marcos P. Santos <tmpsantos@gmail.com> | 2017-10-18 13:11:31 -0700 |
---|---|---|
committer | Thiago Marcos P. Santos <tmpsantos@gmail.com> | 2017-10-18 14:58:29 -0700 |
commit | 90a7cf87a32f6787e57e3852ac9d3015d8112621 (patch) | |
tree | 9f4d18736ee976b0071b54dd0610b8ac0a22a14f /src | |
parent | 1c633072fcea7ad153ab6f8ec40dd72d83541ead (diff) | |
download | qtlocation-mapboxgl-90a7cf87a32f6787e57e3852ac9d3015d8112621.tar.gz |
Bump Mapbox GL Native
mapbox-gl-native @ 10f7af19ce1ec61f37459f9cd75e2a0c89a0c790
Diffstat (limited to 'src')
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 |