diff options
Diffstat (limited to 'src/mbgl')
118 files changed, 1799 insertions, 2111 deletions
diff --git a/src/mbgl/actor/scheduler.cpp b/src/mbgl/actor/scheduler.cpp new file mode 100644 index 0000000000..d7cdb2737b --- /dev/null +++ b/src/mbgl/actor/scheduler.cpp @@ -0,0 +1,19 @@ +#include <mbgl/actor/scheduler.hpp> +#include <mbgl/util/thread_local.hpp> + +namespace mbgl { + +static auto& current() { + static util::ThreadLocal<Scheduler> scheduler; + return scheduler; +}; + +void Scheduler::SetCurrent(Scheduler* scheduler) { + current().set(scheduler); +} + +Scheduler* Scheduler::GetCurrent() { + return current().get(); +} + +} //namespace mbgl 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/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index de38b596d5..34fb576727 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -38,7 +38,7 @@ void RenderAnnotationSource::update(Immutable<style::Source::Impl> baseImpl_, parameters, SourceType::Annotations, util::tileSize, - { 0, 22 }, + { 0, util::DEFAULT_MAX_ZOOM }, [&] (const OverscaledTileID& tileID) { return std::make_unique<AnnotationTile>(tileID, parameters); }); @@ -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..9536b2e101 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> 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 7d57f6863e..6eb555ad1e 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,7 +610,7 @@ ConstrainMode Map::getConstrainMode() const { void Map::setViewportMode(mbgl::ViewportMode mode) { impl->transform.setViewportMode(mode); - impl->onUpdate(Update::Repaint); + impl->onUpdate(); } ViewportMode Map::getViewportMode() const { @@ -618,24 +648,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 +691,7 @@ void Map::cycleDebugOptions() { else impl->debugOptions = MapDebugOptions::TileBorders; - impl->onUpdate(Update::Repaint); + impl->onUpdate(); } MapDebugOptions Map::getDebug() const { @@ -683,18 +715,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 +737,6 @@ void Map::Impl::onUpdate(Update flags) { style->impl->getImageImpls(), style->impl->getSourceImpls(), style->impl->getLayerImpls(), - scheduler, - fileSource, annotationManager, prefetchZoomDelta, bool(stillImageRequest) @@ -727,11 +753,7 @@ void Map::Impl::onStyleLoading() { void Map::Impl::onStyleLoaded() { if (!cameraMutated) { - // Zoom first because it may constrain subsequent operations. - map.setZoom(style->getDefaultZoom()); - map.setLatLng(style->getDefaultLatLng()); - map.setBearing(style->getDefaultBearing()); - map.setPitch(style->getDefaultPitch()); + map.jumpTo(style->getDefaultCamera()); } annotationManager.onStyleLoaded(); diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 4606e3eece..d1a320beae 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -132,7 +132,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 f35f570549..59522d89fd 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 @@ -96,7 +96,7 @@ private: // Limit the amount of zooming possible on the map. double min_scale = std::pow(2, 0); - double max_scale = std::pow(2, 20); + double max_scale = std::pow(2, util::DEFAULT_MAX_ZOOM); double min_pitch = 0.0; double max_pitch = util::PITCH_MAX; diff --git a/src/mbgl/map/update.hpp b/src/mbgl/map/update.hpp deleted file mode 100644 index 057720a5c9..0000000000 --- a/src/mbgl/map/update.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <mbgl/util/traits.hpp> -#include <mbgl/util/util.hpp> - -namespace mbgl { - -enum class Update { - Nothing = 0, - Repaint = 1 << 0, - AnnotationData = 1 << 7 -}; - -MBGL_CONSTEXPR Update operator|(Update lhs, Update rhs) { - return Update(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs)); -} - -MBGL_CONSTEXPR Update& operator|=(Update& lhs, const Update& rhs) { - return (lhs = lhs | rhs); -} - -MBGL_CONSTEXPR bool operator& (Update lhs, Update rhs) { - return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs); -} - -} // namespace mbgl diff --git a/src/mbgl/map/zoom_history.hpp b/src/mbgl/map/zoom_history.hpp index 697e28573c..7821499d72 100644 --- a/src/mbgl/map/zoom_history.hpp +++ b/src/mbgl/map/zoom_history.hpp @@ -8,34 +8,39 @@ namespace mbgl { struct ZoomHistory { float lastZoom; + float lastFloorZoom; float lastIntegerZoom; TimePoint lastIntegerZoomTime; bool first = true; bool update(float z, const TimePoint& now) { constexpr TimePoint zero = TimePoint(Duration::zero()); + const float floorZ = std::floor(z); + if (first) { first = false; - lastIntegerZoom = std::floor(z); + lastIntegerZoom = floorZ; lastIntegerZoomTime = zero; lastZoom = z; + lastFloorZoom = floorZ; + return true; + } + + if (lastFloorZoom > floorZ) { + lastIntegerZoom = floorZ + 1; + lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; + } else if (lastFloorZoom < floorZ) { + lastIntegerZoom = floorZ; + lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; + } + + if (z != lastZoom) { + lastZoom = z; + lastFloorZoom = floorZ; return true; - } else { - if (std::floor(lastZoom) < std::floor(z)) { - lastIntegerZoom = std::floor(z); - lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; - } else if (std::floor(lastZoom) > std::floor(z)) { - lastIntegerZoom = std::floor(z + 1); - lastIntegerZoomTime = now == Clock::time_point::max() ? zero : now; - } - - if (z != lastZoom) { - lastZoom = z; - return true; - } - - return false; } + + return false; } }; diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index 684d9d6099..d023ec7d83 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -23,6 +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, 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 db5c916d32..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) == 8, "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 ed4a09bf10..da9964e623 100644 --- a/src/mbgl/programs/line_program.hpp +++ b/src/mbgl/programs/line_program.hpp @@ -30,7 +30,7 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_gl_units_to_pixels); } // namespace uniforms struct LineLayoutAttributes : gl::Attributes< - attributes::a_pos, + attributes::a_pos_normal, attributes::a_data<uint8_t, 4>> {}; @@ -50,14 +50,17 @@ public: /* * @param p vertex position * @param e extrude normal - * @param t texture normal + * @param round whether the vertex uses a round line cap + * @param up whether the line normal points up or down * @param dir direction of the line cap (-1/0/1) */ - static LayoutVertex layoutVertex(Point<int16_t> p, Point<double> e, Point<bool> t, int8_t dir, int32_t linesofar = 0) { + static LayoutVertex layoutVertex(Point<int16_t> p, Point<double> e, bool round, bool up, int8_t dir, int32_t linesofar = 0) { return LayoutVertex { {{ - static_cast<int16_t>((p.x * 2) | t.x), - static_cast<int16_t>((p.y * 2) | t.y) + p.x, + p.y, + 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/buckets/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp index 194b012eee..a96518df38 100644 --- a/src/mbgl/renderer/buckets/line_bucket.cpp +++ b/src/mbgl/renderer/buckets/line_bucket.cpp @@ -401,7 +401,7 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate, Point<double> extrude = normal; if (endLeft) extrude = extrude - (util::perp(normal) * endLeft); - vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, { round, false }, endLeft, distance * LINE_DISTANCE_SCALE)); + vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, round, false, endLeft, distance * LINE_DISTANCE_SCALE)); e3 = vertices.vertexSize() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); @@ -412,7 +412,7 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate, extrude = normal * -1.0; if (endRight) extrude = extrude - (util::perp(normal) * endRight); - vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, { round, true }, -endRight, distance * LINE_DISTANCE_SCALE)); + vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, round, true, -endRight, distance * LINE_DISTANCE_SCALE)); e3 = vertices.vertexSize() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); @@ -437,7 +437,7 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex, std::size_t startVertex, std::vector<TriangleElement>& triangleStore) { Point<double> flippedExtrude = extrude * (lineTurnsLeft ? -1.0 : 1.0); - vertices.emplace_back(LineProgram::layoutVertex(currentVertex, flippedExtrude, { false, lineTurnsLeft }, 0, distance * LINE_DISTANCE_SCALE)); + vertices.emplace_back(LineProgram::layoutVertex(currentVertex, flippedExtrude, false, lineTurnsLeft, 0, distance * LINE_DISTANCE_SCALE)); e3 = vertices.vertexSize() - 1 - startVertex; if (e1 >= 0 && e2 >= 0) { triangleStore.emplace_back(e1, e2, e3); diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp index 1a0409f456..a66dd42d74 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.cpp +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -69,16 +69,11 @@ void RasterBucket::setMask(TileMask&& mask_) { for (const auto& id : mask) { // Create a quad for every masked tile. const int32_t vertexExtent = util::EXTENT >> id.z; - const int32_t textureExtent = 32768 >> id.z; const Point<int16_t> tlVertex = { static_cast<int16_t>(id.x * vertexExtent), static_cast<int16_t>(id.y * vertexExtent) }; const Point<int16_t> brVertex = { static_cast<int16_t>(tlVertex.x + vertexExtent), static_cast<int16_t>(tlVertex.y + vertexExtent) }; - const Point<uint16_t> tlTexture = { static_cast<uint16_t>(id.x * textureExtent), - static_cast<uint16_t>(id.y * textureExtent) }; - const Point<uint16_t> brTexture = { static_cast<uint16_t>(tlTexture.x + textureExtent), - static_cast<uint16_t>(tlTexture.y + textureExtent) }; if (segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { // Move to a new segments because the old one can't hold the geometry. @@ -86,13 +81,13 @@ void RasterBucket::setMask(TileMask&& mask_) { } vertices.emplace_back( - RasterProgram::layoutVertex({ tlVertex.x, tlVertex.y }, { tlTexture.x, tlTexture.y })); + RasterProgram::layoutVertex({ tlVertex.x, tlVertex.y }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(tlVertex.y) })); vertices.emplace_back( - RasterProgram::layoutVertex({ brVertex.x, tlVertex.y }, { brTexture.x, tlTexture.y })); + RasterProgram::layoutVertex({ brVertex.x, tlVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(tlVertex.y) })); vertices.emplace_back( - RasterProgram::layoutVertex({ tlVertex.x, brVertex.y }, { tlTexture.x, brTexture.y })); + RasterProgram::layoutVertex({ tlVertex.x, brVertex.y }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(brVertex.y) })); vertices.emplace_back( - RasterProgram::layoutVertex({ brVertex.x, brVertex.y }, { brTexture.x, brTexture.y })); + RasterProgram::layoutVertex({ brVertex.x, brVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(brVertex.y) })); auto& segment = segments.back(); assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); 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 2a61a9e993..22cb9563c1 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -64,15 +64,15 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); - auto draw = [&] (uint8_t sublayer, - auto& program, + auto draw = [&] (auto& program, const auto& drawMode, + const auto& depthMode, const auto& indexBuffer, const auto& segments) { program.get(evaluated).draw( parameters.context, drawMode, - parameters.depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite), + depthMode, parameters.stencilModeForClipping(tile.clip), parameters.colorModeForRenderPass(), FillProgram::UniformValues { @@ -93,29 +93,25 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { ); }; - if (evaluated.get<FillAntialias>() && !unevaluated.get<FillOutlineColor>().isUndefined() && parameters.pass == RenderPass::Translucent) { - draw(2, - parameters.programs.fillOutline, - gl::Lines { 2.0f }, - *bucket.lineIndexBuffer, - bucket.lineSegments); - } - // Only draw the fill when it's opaque and we're drawing opaque fragments, // or when it's translucent and we're drawing translucent fragments. if ((evaluated.get<FillColor>().constantOr(Color()).a >= 1.0f && evaluated.get<FillOpacity>().constantOr(0) >= 1.0f) == (parameters.pass == RenderPass::Opaque)) { - draw(1, - parameters.programs.fill, + draw(parameters.programs.fill, gl::Triangles(), + parameters.depthModeForSublayer(1, parameters.pass == RenderPass::Opaque + ? gl::DepthMode::ReadWrite + : gl::DepthMode::ReadOnly), *bucket.triangleIndexBuffer, bucket.triangleSegments); } - if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined() && parameters.pass == RenderPass::Translucent) { - draw(2, - parameters.programs.fillOutline, - gl::Lines { 2.0f }, + if (evaluated.get<FillAntialias>() && parameters.pass == RenderPass::Translucent) { + draw(parameters.programs.fillOutline, + gl::Lines{ 2.0f }, + parameters.depthModeForSublayer( + unevaluated.get<FillOutlineColor>().isUndefined() ? 2 : 0, + gl::DepthMode::ReadOnly), *bucket.lineIndexBuffer, bucket.lineSegments); } @@ -138,15 +134,15 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); - auto draw = [&] (uint8_t sublayer, - auto& program, + auto draw = [&] (auto& program, const auto& drawMode, + const auto& depthMode, const auto& indexBuffer, const auto& segments) { program.get(evaluated).draw( parameters.context, drawMode, - parameters.depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite), + depthMode, parameters.stencilModeForClipping(tile.clip), parameters.colorModeForRenderPass(), FillPatternUniforms::values( @@ -171,21 +167,19 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { ); }; - draw(0, - parameters.programs.fillPattern, + draw(parameters.programs.fillPattern, gl::Triangles(), + parameters.depthModeForSublayer(1, gl::DepthMode::ReadWrite), *bucket.triangleIndexBuffer, bucket.triangleSegments); - if (!evaluated.get<FillAntialias>() || !unevaluated.get<FillOutlineColor>().isUndefined()) { - continue; + if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined()) { + draw(parameters.programs.fillOutlinePattern, + gl::Lines { 2.0f }, + parameters.depthModeForSublayer(2, gl::DepthMode::ReadOnly), + *bucket.lineIndexBuffer, + bucket.lineSegments); } - - draw(2, - parameters.programs.fillOutlinePattern, - gl::Lines { 2.0f }, - *bucket.lineIndexBuffer, - bucket.lineSegments); } } } 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_item.hpp b/src/mbgl/renderer/render_item.hpp deleted file mode 100644 index 4bf5629263..0000000000 --- a/src/mbgl/renderer/render_item.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <mbgl/util/color.hpp> - -#include <unordered_set> -#include <vector> - -namespace mbgl { - -class RenderLayer; -class RenderSource; -class RenderTile; -class Bucket; - -namespace style { -} // namespace style - -class RenderItem { -public: - RenderItem(RenderLayer& layer_, - RenderSource* renderSource_) - : layer(layer_), source(renderSource_) { - } - - RenderLayer& layer; - RenderSource* source; -}; - -class RenderData { -public: - Color backgroundColor; - std::unordered_set<RenderSource*> sources; - std::vector<RenderItem> order; -}; - -} // namespace mbgl 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.cpp b/src/mbgl/renderer/render_static_data.cpp index 4c6028d7b6..ccf239e643 100644 --- a/src/mbgl/renderer/render_static_data.cpp +++ b/src/mbgl/renderer/render_static_data.cpp @@ -32,9 +32,9 @@ static gl::IndexVector<gl::LineStrip> tileLineStripIndices() { static gl::VertexVector<RasterLayoutVertex> rasterVertices() { gl::VertexVector<RasterLayoutVertex> result; result.emplace_back(RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 })); - result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, 0 }, { 32767, 0 })); - result.emplace_back(RasterProgram::layoutVertex({ 0, util::EXTENT }, { 0, 32767 })); - result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 })); + result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, 0 }, { util::EXTENT, 0 })); + result.emplace_back(RasterProgram::layoutVertex({ 0, util::EXTENT }, { 0, util::EXTENT })); + result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, util::EXTENT }, { util::EXTENT, util::EXTENT })); return result; } 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_style.cpp b/src/mbgl/renderer/render_style.cpp deleted file mode 100644 index 3d95b12bc4..0000000000 --- a/src/mbgl/renderer/render_style.cpp +++ /dev/null @@ -1,449 +0,0 @@ -#include <mbgl/renderer/render_style.hpp> -#include <mbgl/renderer/render_style_observer.hpp> -#include <mbgl/renderer/update_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_source.hpp> -#include <mbgl/renderer/render_item.hpp> -#include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/layers/render_background_layer.hpp> -#include <mbgl/renderer/layers/render_circle_layer.hpp> -#include <mbgl/renderer/layers/render_custom_layer.hpp> -#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> -#include <mbgl/renderer/layers/render_fill_layer.hpp> -#include <mbgl/renderer/layers/render_line_layer.hpp> -#include <mbgl/renderer/layers/render_raster_layer.hpp> -#include <mbgl/renderer/layers/render_symbol_layer.hpp> -#include <mbgl/renderer/backend_scope.hpp> -#include <mbgl/renderer/style_diff.hpp> -#include <mbgl/renderer/image_manager.hpp> -#include <mbgl/renderer/query.hpp> -#include <mbgl/style/style.hpp> -#include <mbgl/style/source_impl.hpp> -#include <mbgl/style/transition_options.hpp> -#include <mbgl/sprite/sprite_loader.hpp> -#include <mbgl/text/glyph_manager.hpp> -#include <mbgl/geometry/line_atlas.hpp> -#include <mbgl/tile/tile.hpp> -#include <mbgl/util/math.hpp> -#include <mbgl/util/string.hpp> -#include <mbgl/util/logging.hpp> - -namespace mbgl { - -using namespace style; - -RenderStyleObserver nullObserver; - -RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_) - : scheduler(scheduler_), - fileSource(fileSource_), - 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>()), - observer(&nullObserver) { - glyphManager->setObserver(this); -} - -RenderStyle::~RenderStyle() { - assert(BackendScope::exists()); // Required for custom layers. -} - -void RenderStyle::setObserver(RenderStyleObserver* observer_) { - observer = observer_; -} - -std::vector<const RenderLayer*> RenderStyle::getRenderLayers() const { - std::vector<const RenderLayer*> result; - result.reserve(renderLayers.size()); - for (const auto& layer : *layerImpls) { - result.push_back(getRenderLayer(layer->id)); - } - return result; -} - -RenderLayer* RenderStyle::getRenderLayer(const std::string& id) { - auto it = renderLayers.find(id); - return it != renderLayers.end() ? it->second.get() : nullptr; -} - -const RenderLayer* RenderStyle::getRenderLayer(const std::string& id) const { - auto it = renderLayers.find(id); - return it != renderLayers.end() ? it->second.get() : nullptr; -} - -const RenderLight& RenderStyle::getRenderLight() const { - return renderLight; -} - -void RenderStyle::update(const UpdateParameters& parameters) { - assert(BackendScope::exists()); // Required for custom layers. - - const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint); - - const TransitionParameters transitionParameters { - parameters.timePoint, - parameters.mode == MapMode::Continuous ? parameters.transitionOptions : TransitionOptions() - }; - - const PropertyEvaluationParameters evaluationParameters { - zoomHistory, - parameters.timePoint, - parameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero() - }; - - const TileParameters tileParameters { - parameters.pixelRatio, - parameters.debugOptions, - parameters.transformState, - parameters.scheduler, - parameters.fileSource, - parameters.mode, - parameters.annotationManager, - *imageManager, - *glyphManager, - parameters.prefetchZoomDelta - }; - - glyphManager->setURL(parameters.glyphURL); - - // Update light. - const bool lightChanged = renderLight.impl != parameters.light; - - if (lightChanged) { - renderLight.impl = parameters.light; - renderLight.transition(transitionParameters); - } - - if (lightChanged || zoomChanged || renderLight.hasTransition()) { - renderLight.evaluate(evaluationParameters); - } - - - const ImageDifference imageDiff = diffImages(imageImpls, parameters.images); - imageImpls = parameters.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(parameters.spriteLoaded); - - - const LayerDifference layerDiff = diffLayers(layerImpls, parameters.layers); - layerImpls = parameters.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, parameters.sources); - sourceImpls = parameters.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)); - } - - // 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 && ( - hasLayoutDifference(layerDiff, layer->id) || - !imageDiff.added.empty() || - !imageDiff.removed.empty() || - !imageDiff.changed.empty())) { - needsRelayout = true; - } - - filteredLayers.push_back(layer); - } - - renderSources.at(source->id)->update(source, - filteredLayers, - needsRendering, - needsRelayout, - tileParameters); - } -} - -RenderSource* RenderStyle::getRenderSource(const std::string& id) const { - auto it = renderSources.find(id); - return it != renderSources.end() ? it->second.get() : nullptr; -} - -bool RenderStyle::hasTransitions() const { - if (renderLight.hasTransition()) { - return true; - } - - for (const auto& entry : renderLayers) { - if (entry.second->hasTransition()) { - return true; - } - } - - return false; -} - -bool RenderStyle::isLoaded() const { - for (const auto& entry: renderSources) { - if (!entry.second->isLoaded()) { - return false; - } - } - - if (!imageManager->isLoaded()) { - return false; - } - - return true; -} - -RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) { - RenderData result; - - for (const auto& entry : renderSources) { - if (entry.second->isEnabled()) { - result.sources.insert(entry.second.get()); - } - } - - for (auto& layerImpl : *layerImpls) { - RenderLayer* layer = getRenderLayer(layerImpl->id); - assert(layer); - - if (!layer->needsRendering(zoomHistory.lastZoom)) { - continue; - } - - if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) { - if (debugOptions & MapDebugOptions::Overdraw) { - // We want to skip glClear optimization in overdraw mode. - result.order.emplace_back(*layer, nullptr); - continue; - } - 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(). - result.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. - result.order.emplace_back(*layer, nullptr); - } - continue; - } - - if (layer->is<RenderCustomLayer>()) { - result.order.emplace_back(*layer, nullptr); - continue; - } - - RenderSource* source = getRenderSource(layer->baseImpl->source); - if (!source) { - Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str()); - continue; - } - - 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(), - [angle](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); - - auto par = util::rotate(pa, angle); - auto pbr = util::rotate(pb, angle); - - 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; - } - } - layer->setRenderTiles(std::move(sortedTilesForInsertion)); - result.order.emplace_back(*layer, source); - } - - return result; -} - -std::vector<Feature> RenderStyle::queryRenderedFeatures(const ScreenLineString& geometry, - const TransformState& transformState, - const RenderedQueryOptions& options) const { - std::unordered_map<std::string, std::vector<Feature>> resultsByLayer; - - if (options.layerIDs) { - std::unordered_set<std::string> sourceIDs; - for (const auto& layerID : *options.layerIDs) { - if (const RenderLayer* layer = getRenderLayer(layerID)) { - sourceIDs.emplace(layer->baseImpl->source); - } - } - for (const auto& sourceID : sourceIDs) { - if (RenderSource* renderSource = getRenderSource(sourceID)) { - auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, *this, options); - std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); - } - } - } else { - for (const auto& entry : renderSources) { - auto sourceResults = entry.second->queryRenderedFeatures(geometry, transformState, *this, 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; -} - -void RenderStyle::onLowMemory() { - for (const auto& entry : renderSources) { - entry.second->onLowMemory(); - } -} - -void RenderStyle::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 RenderStyle::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 RenderStyle::onTileChanged(RenderSource&, const OverscaledTileID&) { - observer->onInvalidate(); -} - -void RenderStyle::dumpDebugLogs() const { - for (const auto& entry : renderSources) { - entry.second->dumpDebugLogs(); - } - - imageManager->dumpDebugLogs(); -} - -} // namespace mbgl diff --git a/src/mbgl/renderer/render_style.hpp b/src/mbgl/renderer/render_style.hpp deleted file mode 100644 index 23a640c482..0000000000 --- a/src/mbgl/renderer/render_style.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include <mbgl/style/image.hpp> -#include <mbgl/renderer/render_source.hpp> -#include <mbgl/renderer/render_source_observer.hpp> -#include <mbgl/renderer/render_layer.hpp> -#include <mbgl/renderer/render_light.hpp> -#include <mbgl/text/glyph_manager_observer.hpp> -#include <mbgl/map/zoom_history.hpp> -#include <mbgl/map/mode.hpp> - -#include <memory> -#include <string> -#include <vector> - -namespace mbgl { - -class FileSource; -class GlyphManager; -class ImageManager; -class LineAtlas; -class RenderData; -class TransformState; -class RenderedQueryOptions; -class Scheduler; -class UpdateParameters; -class RenderStyleObserver; - -namespace style { -class Image; -class Source; -class Layer; -} // namespace style - -class RenderStyle : public GlyphManagerObserver, - public RenderSourceObserver { -public: - RenderStyle(Scheduler&, FileSource&); - ~RenderStyle() final; - - void setObserver(RenderStyleObserver*); - void update(const UpdateParameters&); - - bool isLoaded() const; - bool hasTransitions() const; - - RenderSource* getRenderSource(const std::string& id) const; - - std::vector<const RenderLayer*> getRenderLayers() const; - - RenderLayer* getRenderLayer(const std::string& id); - const RenderLayer* getRenderLayer(const std::string& id) const; - - const RenderLight& getRenderLight() const; - - RenderData getRenderData(MapDebugOptions, float angle); - - std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry, - const TransformState& transformState, - const RenderedQueryOptions& options) const; - - void onLowMemory(); - - void dumpDebugLogs() const; - - Scheduler& scheduler; - FileSource& fileSource; - std::unique_ptr<GlyphManager> glyphManager; - std::unique_ptr<ImageManager> imageManager; - std::unique_ptr<LineAtlas> lineAtlas; - -private: - 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; - - // 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; - - RenderStyleObserver* observer; - ZoomHistory zoomHistory; -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/render_style_observer.hpp b/src/mbgl/renderer/render_style_observer.hpp deleted file mode 100644 index 5852dd68b8..0000000000 --- a/src/mbgl/renderer/render_style_observer.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include <exception> - -namespace mbgl { - -class RenderStyleObserver { -public: - virtual ~RenderStyleObserver() = default; - virtual void onInvalidate() {} - virtual void onResourceError(std::exception_ptr) {} -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index c9912f0563..8df31f8d7c 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -74,57 +74,75 @@ void RenderTile::finishRender(PaintParameters& parameters) { static const style::Properties<>::PossiblyEvaluated properties {}; static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0); - auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) { + if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) { + if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() || + tile.debugBucket->complete != tile.isComplete() || + !(tile.debugBucket->modified == tile.modified) || + !(tile.debugBucket->expires == tile.expires) || + tile.debugBucket->debugMode != parameters.debugOptions) { + tile.debugBucket = std::make_unique<DebugBucket>( + tile.id, tile.isRenderable(), tile.isComplete(), tile.modified, + tile.expires, parameters.debugOptions, parameters.context); + } + parameters.programs.debug.draw( parameters.context, - drawMode, + gl::Lines { 4.0f * parameters.pixelRatio }, gl::DepthMode::disabled(), parameters.stencilModeForClipping(clip), gl::ColorMode::unblended(), DebugProgram::UniformValues { uniforms::u_matrix::Value{ matrix }, - uniforms::u_color::Value{ color } + uniforms::u_color::Value{ Color::white() } }, - vertexBuffer, - indexBuffer, - segments, + *tile.debugBucket->vertexBuffer, + *tile.debugBucket->indexBuffer, + tile.debugBucket->segments, paintAttibuteData, properties, parameters.state.getZoom(), "debug" ); - }; - - if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) { - if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() || - tile.debugBucket->complete != tile.isComplete() || - !(tile.debugBucket->modified == tile.modified) || - !(tile.debugBucket->expires == tile.expires) || - tile.debugBucket->debugMode != parameters.debugOptions) { - tile.debugBucket = std::make_unique<DebugBucket>( - tile.id, tile.isRenderable(), tile.isComplete(), tile.modified, - tile.expires, parameters.debugOptions, parameters.context); - } - draw(Color::white(), - *tile.debugBucket->vertexBuffer, - *tile.debugBucket->indexBuffer, - tile.debugBucket->segments, - gl::Lines { 4.0f * parameters.pixelRatio }); - - draw(Color::black(), - *tile.debugBucket->vertexBuffer, - *tile.debugBucket->indexBuffer, - tile.debugBucket->segments, - gl::Lines { 2.0f * parameters.pixelRatio }); + parameters.programs.debug.draw( + parameters.context, + gl::Lines { 2.0f * parameters.pixelRatio }, + gl::DepthMode::disabled(), + parameters.stencilModeForClipping(clip), + gl::ColorMode::unblended(), + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_color::Value{ Color::black() } + }, + *tile.debugBucket->vertexBuffer, + *tile.debugBucket->indexBuffer, + tile.debugBucket->segments, + paintAttibuteData, + properties, + parameters.state.getZoom(), + "debug" + ); } if (parameters.debugOptions & MapDebugOptions::TileBorders) { - draw(Color::red(), - parameters.staticData.tileVertexBuffer, - parameters.staticData.tileBorderIndexBuffer, - parameters.staticData.tileBorderSegments, - gl::LineStrip { 4.0f * parameters.pixelRatio }); + parameters.programs.debug.draw( + parameters.context, + gl::LineStrip { 4.0f * parameters.pixelRatio }, + gl::DepthMode::disabled(), + parameters.stencilModeForClipping(clip), + gl::ColorMode::unblended(), + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_color::Value{ Color::red() } + }, + parameters.staticData.tileVertexBuffer, + parameters.staticData.tileBorderIndexBuffer, + parameters.staticData.tileBorderSegments, + paintAttibuteData, + properties, + parameters.state.getZoom(), + "debug" + ); } } 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..1a828b80a3 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,131 @@ 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; + } + } + layer->setRenderTiles(std::move(sortedTilesForInsertion)); + order.emplace_back(RenderItem { *layer, source }); + } frameHistory.record(parameters.timePoint, parameters.state.getZoom(), @@ -130,6 +388,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 +431,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 +439,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 +504,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 +514,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 +522,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 +530,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 +538,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 +549,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 +584,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..72ab4879ef 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> diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 11ff8c26b1..9140e01711 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -10,6 +10,7 @@ #include <mbgl/util/tile_coordinate.hpp> #include <mbgl/util/tile_cover.hpp> #include <mbgl/util/logging.hpp> +#include <mbgl/util/constants.hpp> namespace mbgl { @@ -82,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>> {}; } @@ -193,11 +194,11 @@ void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_, bucket->vertices.emplace_back( RasterProgram::layoutVertex({ geomCoords[0].x, geomCoords[0].y }, { 0, 0 })); bucket->vertices.emplace_back( - RasterProgram::layoutVertex({ geomCoords[1].x, geomCoords[1].y }, { 32767, 0 })); + RasterProgram::layoutVertex({ geomCoords[1].x, geomCoords[1].y }, { util::EXTENT, 0 })); bucket->vertices.emplace_back( - RasterProgram::layoutVertex({ geomCoords[3].x, geomCoords[3].y }, { 0, 32767 })); + RasterProgram::layoutVertex({ geomCoords[3].x, geomCoords[3].y }, { 0, util::EXTENT })); bucket->vertices.emplace_back( - RasterProgram::layoutVertex({ geomCoords[2].x, geomCoords[2].y }, { 32767, 32767 })); + RasterProgram::layoutVertex({ geomCoords[2].x, geomCoords[2].y }, { util::EXTENT, util::EXTENT })); bucket->indices.emplace_back(0, 1, 2); bucket->indices.emplace_back(1, 2, 3); diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index fc1a462090..7b69d09fa7 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; 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..01de812309 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> 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..5e5c6d1108 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> diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 219f154675..6cd9bd9ebd 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -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(Tile::Necessity::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..73a8d34c1c 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; @@ -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/circle.cpp b/src/mbgl/shaders/circle.cpp index 953e750776..c14335914b 100644 --- a/src/mbgl/shaders/circle.cpp +++ b/src/mbgl/shaders/circle.cpp @@ -24,6 +24,7 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_radius uniform lowp float a_radius_t; attribute mediump vec2 a_radius; @@ -32,6 +33,7 @@ varying mediump float radius; uniform mediump float u_radius; #endif + #ifndef HAS_UNIFORM_u_blur uniform lowp float a_blur_t; attribute lowp vec2 a_blur; @@ -40,6 +42,7 @@ varying lowp float blur; uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; @@ -48,6 +51,7 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_stroke_color uniform lowp float a_stroke_color_t; attribute highp vec4 a_stroke_color; @@ -56,6 +60,7 @@ varying highp vec4 stroke_color; uniform highp vec4 u_stroke_color; #endif + #ifndef HAS_UNIFORM_u_stroke_width uniform lowp float a_stroke_width_t; attribute mediump vec2 a_stroke_width; @@ -64,6 +69,7 @@ varying mediump float stroke_width; uniform mediump float u_stroke_width; #endif + #ifndef HAS_UNIFORM_u_stroke_opacity uniform lowp float a_stroke_opacity_t; attribute lowp vec2 a_stroke_opacity; @@ -72,52 +78,60 @@ varying lowp float stroke_opacity; uniform lowp float u_stroke_opacity; #endif + varying vec3 v_data; void main(void) { - + #ifndef HAS_UNIFORM_u_color color = unpack_mix_vec4(a_color, a_color_t); #else highp vec4 color = u_color; #endif + #ifndef HAS_UNIFORM_u_radius radius = unpack_mix_vec2(a_radius, a_radius_t); #else mediump float radius = u_radius; #endif + #ifndef HAS_UNIFORM_u_blur blur = unpack_mix_vec2(a_blur, a_blur_t); #else lowp float blur = u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + #ifndef HAS_UNIFORM_u_stroke_color stroke_color = unpack_mix_vec4(a_stroke_color, a_stroke_color_t); #else highp vec4 stroke_color = u_stroke_color; #endif + #ifndef HAS_UNIFORM_u_stroke_width stroke_width = unpack_mix_vec2(a_stroke_width, a_stroke_width_t); #else mediump float stroke_width = u_stroke_width; #endif + #ifndef HAS_UNIFORM_u_stroke_opacity stroke_opacity = unpack_mix_vec2(a_stroke_opacity, a_stroke_opacity_t); #else lowp float stroke_opacity = u_stroke_opacity; #endif + // unencode the extrusion vector that we snuck into the a_pos vector vec2 extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0); @@ -164,74 +178,88 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_radius varying mediump float radius; #else uniform mediump float u_radius; #endif + #ifndef HAS_UNIFORM_u_blur varying lowp float blur; #else uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_stroke_color varying highp vec4 stroke_color; #else uniform highp vec4 u_stroke_color; #endif + #ifndef HAS_UNIFORM_u_stroke_width varying mediump float stroke_width; #else uniform mediump float u_stroke_width; #endif + #ifndef HAS_UNIFORM_u_stroke_opacity varying lowp float stroke_opacity; #else uniform lowp float u_stroke_opacity; #endif + varying vec3 v_data; void main() { - + #ifdef HAS_UNIFORM_u_color highp vec4 color = u_color; #endif + #ifdef HAS_UNIFORM_u_radius mediump float radius = u_radius; #endif + #ifdef HAS_UNIFORM_u_blur lowp float blur = u_blur; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + #ifdef HAS_UNIFORM_u_stroke_color highp vec4 stroke_color = u_stroke_color; #endif + #ifdef HAS_UNIFORM_u_stroke_width mediump float stroke_width = u_stroke_width; #endif + #ifdef HAS_UNIFORM_u_stroke_opacity lowp float stroke_opacity = u_stroke_opacity; #endif + vec2 extrude = v_data.xy; float extrude_length = length(extrude); diff --git a/src/mbgl/shaders/debug.cpp b/src/mbgl/shaders/debug.cpp index d39dcf25be..d18f3be5d1 100644 --- a/src/mbgl/shaders/debug.cpp +++ b/src/mbgl/shaders/debug.cpp @@ -12,7 +12,12 @@ attribute vec2 a_pos; uniform mat4 u_matrix; void main() { - gl_Position = u_matrix * vec4(a_pos, step(32767.0, a_pos.x), 1); + // We are using Int16 for texture position coordinates to give us enough precision for + // fractional coordinates. We use 8192 to scale the texture coordinates in the buffer + // as an arbitrarily high number to preserve adequate precision when rendering. + // This is also the same value as the EXTENT we are using for our tile buffer pos coordinates, + // so math for modifying either is consistent. + gl_Position = u_matrix * vec4(a_pos, step(8192.0, a_pos.x), 1); } )MBGL_SHADER"; diff --git a/src/mbgl/shaders/fill.cpp b/src/mbgl/shaders/fill.cpp index 8f5f304014..3ba00836a2 100644 --- a/src/mbgl/shaders/fill.cpp +++ b/src/mbgl/shaders/fill.cpp @@ -20,6 +20,7 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; @@ -28,20 +29,23 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_color color = unpack_mix_vec4(a_color, a_color_t); #else highp vec4 color = u_color; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + gl_Position = u_matrix * vec4(a_pos, 0, 1); } @@ -54,22 +58,26 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifdef HAS_UNIFORM_u_color highp vec4 color = u_color; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + gl_FragColor = color * opacity; #ifdef OVERDRAW_INSPECTOR diff --git a/src/mbgl/shaders/fill_extrusion.cpp b/src/mbgl/shaders/fill_extrusion.cpp index ad14e4f32e..817f73391c 100644 --- a/src/mbgl/shaders/fill_extrusion.cpp +++ b/src/mbgl/shaders/fill_extrusion.cpp @@ -27,6 +27,7 @@ varying lowp float base; uniform lowp float u_base; #endif + #ifndef HAS_UNIFORM_u_height uniform lowp float a_height_t; attribute lowp vec2 a_height; @@ -36,6 +37,7 @@ uniform lowp float u_height; #endif + #ifndef HAS_UNIFORM_u_color uniform lowp float a_color_t; attribute highp vec4 a_color; @@ -44,26 +46,30 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_base base = unpack_mix_vec2(a_base, a_base_t); #else lowp float base = u_base; #endif + #ifndef HAS_UNIFORM_u_height height = unpack_mix_vec2(a_height, a_height_t); #else lowp float height = u_height; #endif + #ifndef HAS_UNIFORM_u_color color = unpack_mix_vec4(a_color, a_color_t); #else highp vec4 color = u_color; #endif + base = max(0.0, base); height = max(0.0, height); @@ -113,32 +119,38 @@ varying lowp float base; uniform lowp float u_base; #endif + #ifndef HAS_UNIFORM_u_height varying lowp float height; #else uniform lowp float u_height; #endif + #ifndef HAS_UNIFORM_u_color varying highp vec4 color; #else uniform highp vec4 u_color; #endif -void main() { +void main() { + #ifdef HAS_UNIFORM_u_base lowp float base = u_base; #endif + #ifdef HAS_UNIFORM_u_height lowp float height = u_height; #endif + #ifdef HAS_UNIFORM_u_color highp vec4 color = u_color; #endif + gl_FragColor = v_color; #ifdef OVERDRAW_INSPECTOR diff --git a/src/mbgl/shaders/fill_extrusion_pattern.cpp b/src/mbgl/shaders/fill_extrusion_pattern.cpp index 2681973af6..d3e5eef1bf 100644 --- a/src/mbgl/shaders/fill_extrusion_pattern.cpp +++ b/src/mbgl/shaders/fill_extrusion_pattern.cpp @@ -39,6 +39,7 @@ varying lowp float base; uniform lowp float u_base; #endif + #ifndef HAS_UNIFORM_u_height uniform lowp float a_height_t; attribute lowp vec2 a_height; @@ -47,20 +48,23 @@ varying lowp float height; uniform lowp float u_height; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_base base = unpack_mix_vec2(a_base, a_base_t); #else lowp float base = u_base; #endif + #ifndef HAS_UNIFORM_u_height height = unpack_mix_vec2(a_height, a_height_t); #else lowp float height = u_height; #endif + base = max(0.0, base); height = max(0.0, height); @@ -109,22 +113,26 @@ varying lowp float base; uniform lowp float u_base; #endif + #ifndef HAS_UNIFORM_u_height varying lowp float height; #else uniform lowp float u_height; #endif -void main() { +void main() { + #ifdef HAS_UNIFORM_u_base lowp float base = u_base; #endif + #ifdef HAS_UNIFORM_u_height lowp float height = u_height; #endif + vec2 imagecoord = mod(v_pos_a, 1.0); vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); vec4 color1 = texture2D(u_image, pos); diff --git a/src/mbgl/shaders/fill_outline.cpp b/src/mbgl/shaders/fill_outline.cpp index 18a4d8c0a8..9ade598d10 100644 --- a/src/mbgl/shaders/fill_outline.cpp +++ b/src/mbgl/shaders/fill_outline.cpp @@ -23,6 +23,7 @@ varying highp vec4 outline_color; uniform highp vec4 u_outline_color; #endif + #ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; @@ -31,20 +32,23 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_outline_color outline_color = unpack_mix_vec4(a_outline_color, a_outline_color_t); #else highp vec4 outline_color = u_outline_color; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + gl_Position = u_matrix * vec4(a_pos, 0, 1); v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world; } @@ -58,24 +62,28 @@ varying highp vec4 outline_color; uniform highp vec4 u_outline_color; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif + varying vec2 v_pos; void main() { - + #ifdef HAS_UNIFORM_u_outline_color highp vec4 outline_color = u_outline_color; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + float dist = length(v_pos - gl_FragCoord.xy); float alpha = 1.0 - smoothstep(0.0, 1.0, dist); gl_FragColor = outline_color * (alpha * opacity); diff --git a/src/mbgl/shaders/fill_outline_pattern.cpp b/src/mbgl/shaders/fill_outline_pattern.cpp index 68e69c2135..11cddb7d07 100644 --- a/src/mbgl/shaders/fill_outline_pattern.cpp +++ b/src/mbgl/shaders/fill_outline_pattern.cpp @@ -32,14 +32,16 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + gl_Position = u_matrix * vec4(a_pos, 0, 1); v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos); @@ -70,12 +72,14 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + vec2 imagecoord = mod(v_pos_a, 1.0); vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); vec4 color1 = texture2D(u_image, pos); diff --git a/src/mbgl/shaders/fill_pattern.cpp b/src/mbgl/shaders/fill_pattern.cpp index f6f9e2fbff..a3817c4426 100644 --- a/src/mbgl/shaders/fill_pattern.cpp +++ b/src/mbgl/shaders/fill_pattern.cpp @@ -30,14 +30,16 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + gl_Position = u_matrix * vec4(a_pos, 0, 1); v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos); @@ -65,12 +67,14 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + vec2 imagecoord = mod(v_pos_a, 1.0); vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); vec4 color1 = texture2D(u_image, pos); diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp index 1eb92c4b71..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 vec2 a_pos; +attribute vec4 a_pos_normal; attribute vec4 a_data; uniform mat4 u_matrix; @@ -41,6 +41,7 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_blur uniform lowp float a_blur_t; attribute lowp vec2 a_blur; @@ -49,6 +50,7 @@ varying lowp float blur; uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; @@ -57,6 +59,7 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_gapwidth uniform lowp float a_gapwidth_t; attribute mediump vec2 a_gapwidth; @@ -64,6 +67,7 @@ attribute mediump vec2 a_gapwidth; uniform mediump float u_gapwidth; #endif + #ifndef HAS_UNIFORM_u_offset uniform lowp float a_offset_t; attribute lowp vec2 a_offset; @@ -71,6 +75,7 @@ attribute lowp vec2 a_offset; uniform lowp float u_offset; #endif + #ifndef HAS_UNIFORM_u_width uniform lowp float a_width_t; attribute mediump vec2 a_width; @@ -78,61 +83,66 @@ attribute mediump vec2 a_width; uniform mediump float u_width; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_color color = unpack_mix_vec4(a_color, a_color_t); #else highp vec4 color = u_color; #endif + #ifndef HAS_UNIFORM_u_blur blur = unpack_mix_vec2(a_blur, a_blur_t); #else lowp float blur = u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + #ifndef HAS_UNIFORM_u_gapwidth mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); #else mediump float gapwidth = u_gapwidth; #endif + #ifndef HAS_UNIFORM_u_offset lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); #else lowp float offset = u_offset; #endif + #ifndef HAS_UNIFORM_u_width mediump float width = unpack_mix_vec2(a_width, a_width_t); #else mediump float width = u_width; #endif + vec2 a_extrude = a_data.xy - 128.0; float a_direction = mod(a_data.z, 4.0) - 1.0; - // We store the texture normals in the most insignificant bit - // transform y 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 + vec2 pos = a_pos_normal.xy; + + // 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 = mod(a_pos, 2.0); - 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. - // moved them into the shader for clarity and simplicity. + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. gapwidth = gapwidth / 2.0; float halfwidth = width / 2.0; - offset = -1.0 * offset; + offset = -1.0 * offset; float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING; @@ -149,9 +159,6 @@ void main() { mediump float t = 1.0 - abs(u); mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); - // Remove the texture normal bit to get the position - vec2 pos = floor(a_pos * 0.5); - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; @@ -172,36 +179,42 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_blur varying lowp float blur; #else uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif + varying vec2 v_width2; varying vec2 v_normal; varying float v_gamma_scale; void main() { - + #ifdef HAS_UNIFORM_u_color highp vec4 color = u_color; #endif + #ifdef HAS_UNIFORM_u_blur lowp float blur = u_blur; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + // Calculate the distance of the pixel from the line in pixels. float dist = length(v_normal) * v_width2.s; diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp index 222042a13c..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 vec2 a_pos; +attribute vec4 a_pos_normal; attribute vec4 a_data; uniform mat4 u_matrix; @@ -44,6 +44,7 @@ varying lowp float blur; uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; @@ -52,6 +53,7 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_offset uniform lowp float a_offset_t; attribute lowp vec2 a_offset; @@ -59,6 +61,7 @@ attribute lowp vec2 a_offset; uniform lowp float u_offset; #endif + #ifndef HAS_UNIFORM_u_gapwidth uniform lowp float a_gapwidth_t; attribute mediump vec2 a_gapwidth; @@ -66,6 +69,7 @@ attribute mediump vec2 a_gapwidth; uniform mediump float u_gapwidth; #endif + #ifndef HAS_UNIFORM_u_width uniform lowp float a_width_t; attribute mediump vec2 a_width; @@ -73,55 +77,60 @@ attribute mediump vec2 a_width; uniform mediump float u_width; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_blur blur = unpack_mix_vec2(a_blur, a_blur_t); #else lowp float blur = u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + #ifndef HAS_UNIFORM_u_offset lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); #else lowp float offset = u_offset; #endif + #ifndef HAS_UNIFORM_u_gapwidth mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); #else mediump float gapwidth = u_gapwidth; #endif + #ifndef HAS_UNIFORM_u_width mediump float width = unpack_mix_vec2(a_width, a_width_t); #else mediump float width = u_width; #endif + vec2 a_extrude = a_data.xy - 128.0; float a_direction = mod(a_data.z, 4.0) - 1.0; float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; - // We store the texture normals in the most insignificant bit - // transform y 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 + vec2 pos = a_pos_normal.xy; + + // 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 = mod(a_pos, 2.0); - 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. - // moved them into the shader for clarity and simplicity. + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. gapwidth = gapwidth / 2.0; float halfwidth = width / 2.0; - offset = -1.0 * offset; + offset = -1.0 * offset; float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING; @@ -138,9 +147,6 @@ void main() { mediump float t = 1.0 - abs(u); mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); - // Remove the texture normal bit to get the position - vec2 pos = floor(a_pos * 0.5); - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; @@ -178,22 +184,26 @@ varying lowp float blur; uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif -void main() { +void main() { + #ifdef HAS_UNIFORM_u_blur lowp float blur = u_blur; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + // Calculate the distance of the pixel from the line in pixels. float dist = length(v_normal) * v_width2.s; diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp index 168f4ca98d..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 vec2 a_pos; +attribute vec4 a_pos_normal; attribute vec4 a_data; uniform mat4 u_matrix; @@ -49,6 +49,7 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_blur uniform lowp float a_blur_t; attribute lowp vec2 a_blur; @@ -57,6 +58,7 @@ varying lowp float blur; uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; @@ -65,6 +67,7 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_gapwidth uniform lowp float a_gapwidth_t; attribute mediump vec2 a_gapwidth; @@ -72,6 +75,7 @@ attribute mediump vec2 a_gapwidth; uniform mediump float u_gapwidth; #endif + #ifndef HAS_UNIFORM_u_offset uniform lowp float a_offset_t; attribute lowp vec2 a_offset; @@ -79,6 +83,7 @@ attribute lowp vec2 a_offset; uniform lowp float u_offset; #endif + #ifndef HAS_UNIFORM_u_width uniform lowp float a_width_t; attribute mediump vec2 a_width; @@ -87,6 +92,7 @@ varying mediump float width; uniform mediump float u_width; #endif + #ifndef HAS_UNIFORM_u_floorwidth uniform lowp float a_floorwidth_t; attribute lowp vec2 a_floorwidth; @@ -95,68 +101,75 @@ varying lowp float floorwidth; uniform lowp float u_floorwidth; #endif -void main() { +void main() { + #ifndef HAS_UNIFORM_u_color color = unpack_mix_vec4(a_color, a_color_t); #else highp vec4 color = u_color; #endif + #ifndef HAS_UNIFORM_u_blur blur = unpack_mix_vec2(a_blur, a_blur_t); #else lowp float blur = u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + #ifndef HAS_UNIFORM_u_gapwidth mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); #else mediump float gapwidth = u_gapwidth; #endif + #ifndef HAS_UNIFORM_u_offset lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); #else lowp float offset = u_offset; #endif + #ifndef HAS_UNIFORM_u_width width = unpack_mix_vec2(a_width, a_width_t); #else mediump float width = u_width; #endif + #ifndef HAS_UNIFORM_u_floorwidth floorwidth = unpack_mix_vec2(a_floorwidth, a_floorwidth_t); #else lowp float floorwidth = u_floorwidth; #endif + vec2 a_extrude = a_data.xy - 128.0; float a_direction = mod(a_data.z, 4.0) - 1.0; float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; - // We store the texture normals in the most insignificant bit - // transform y 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 + vec2 pos = a_pos_normal.xy; + + // 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 = mod(a_pos, 2.0); - 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. - // moved them into the shader for clarity and simplicity. + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. gapwidth = gapwidth / 2.0; float halfwidth = width / 2.0; offset = -1.0 * offset; - + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING; @@ -172,9 +185,6 @@ void main() { mediump float t = 1.0 - abs(u); mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); - // Remove the texture normal bit to get the position - vec2 pos = floor(a_pos * 0.5); - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; @@ -209,52 +219,62 @@ varying highp vec4 color; uniform highp vec4 u_color; #endif + #ifndef HAS_UNIFORM_u_blur varying lowp float blur; #else uniform lowp float u_blur; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_width varying mediump float width; #else uniform mediump float u_width; #endif + #ifndef HAS_UNIFORM_u_floorwidth varying lowp float floorwidth; #else uniform lowp float u_floorwidth; #endif -void main() { +void main() { + #ifdef HAS_UNIFORM_u_color highp vec4 color = u_color; #endif + #ifdef HAS_UNIFORM_u_blur lowp float blur = u_blur; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + #ifdef HAS_UNIFORM_u_width mediump float width = u_width; #endif + #ifdef HAS_UNIFORM_u_floorwidth lowp float floorwidth = u_floorwidth; #endif + // Calculate the distance of the pixel from the line in pixels. float dist = length(v_normal) * v_width2.s; diff --git a/src/mbgl/shaders/raster.cpp b/src/mbgl/shaders/raster.cpp index f454078310..98291bfec6 100644 --- a/src/mbgl/shaders/raster.cpp +++ b/src/mbgl/shaders/raster.cpp @@ -20,7 +20,12 @@ varying vec2 v_pos1; void main() { gl_Position = u_matrix * vec4(a_pos, 0, 1); - v_pos0 = (((a_texture_pos / 32767.0) - 0.5) / u_buffer_scale ) + 0.5; + // We are using Int16 for texture position coordinates to give us enough precision for + // fractional coordinates. We use 8192 to scale the texture coordinates in the buffer + // as an arbitrarily high number to preserve adequate precision when rendering. + // This is also the same value as the EXTENT we are using for our tile buffer pos coordinates, + // so math for modifying either is consistent. + v_pos0 = (((a_texture_pos / 8192.0) - 0.5) / u_buffer_scale ) + 0.5; v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent; } diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp index c0e3a0ac01..1e96194738 100644 --- a/src/mbgl/shaders/symbol_icon.cpp +++ b/src/mbgl/shaders/symbol_icon.cpp @@ -32,6 +32,7 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif + uniform mat4 u_matrix; uniform mat4 u_label_plane_matrix; uniform mat4 u_gl_coord_matrix; @@ -45,13 +46,14 @@ varying vec2 v_tex; varying vec2 v_fade_tex; void main() { - + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + vec2 a_pos = a_pos_offset.xy; vec2 a_offset = a_pos_offset.zw; @@ -125,15 +127,17 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif + varying vec2 v_tex; varying vec2 v_fade_tex; void main() { - + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + lowp float alpha = texture2D(u_fadetexture, v_fade_tex).a * opacity; gl_FragColor = texture2D(u_texture, v_tex) * alpha; diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index 2050886957..a4427f31ab 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -34,6 +34,7 @@ varying highp vec4 fill_color; uniform highp vec4 u_fill_color; #endif + #ifndef HAS_UNIFORM_u_halo_color uniform lowp float a_halo_color_t; attribute highp vec4 a_halo_color; @@ -42,6 +43,7 @@ varying highp vec4 halo_color; uniform highp vec4 u_halo_color; #endif + #ifndef HAS_UNIFORM_u_opacity uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; @@ -50,6 +52,7 @@ varying lowp float opacity; uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_halo_width uniform lowp float a_halo_width_t; attribute lowp vec2 a_halo_width; @@ -58,6 +61,7 @@ varying lowp float halo_width; uniform lowp float u_halo_width; #endif + #ifndef HAS_UNIFORM_u_halo_blur uniform lowp float a_halo_blur_t; attribute lowp vec2 a_halo_blur; @@ -66,6 +70,7 @@ varying lowp float halo_blur; uniform lowp float u_halo_blur; #endif + uniform mat4 u_matrix; uniform mat4 u_label_plane_matrix; uniform mat4 u_gl_coord_matrix; @@ -84,37 +89,42 @@ varying vec4 v_data0; varying vec2 v_data1; void main() { - + #ifndef HAS_UNIFORM_u_fill_color fill_color = unpack_mix_vec4(a_fill_color, a_fill_color_t); #else highp vec4 fill_color = u_fill_color; #endif + #ifndef HAS_UNIFORM_u_halo_color halo_color = unpack_mix_vec4(a_halo_color, a_halo_color_t); #else highp vec4 halo_color = u_halo_color; #endif + #ifndef HAS_UNIFORM_u_opacity opacity = unpack_mix_vec2(a_opacity, a_opacity_t); #else lowp float opacity = u_opacity; #endif + #ifndef HAS_UNIFORM_u_halo_width halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t); #else lowp float halo_width = u_halo_width; #endif + #ifndef HAS_UNIFORM_u_halo_blur halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t); #else lowp float halo_blur = u_halo_blur; #endif + vec2 a_pos = a_pos_offset.xy; vec2 a_offset = a_pos_offset.zw; @@ -215,30 +225,35 @@ varying highp vec4 fill_color; uniform highp vec4 u_fill_color; #endif + #ifndef HAS_UNIFORM_u_halo_color varying highp vec4 halo_color; #else uniform highp vec4 u_halo_color; #endif + #ifndef HAS_UNIFORM_u_opacity varying lowp float opacity; #else uniform lowp float u_opacity; #endif + #ifndef HAS_UNIFORM_u_halo_width varying lowp float halo_width; #else uniform lowp float u_halo_width; #endif + #ifndef HAS_UNIFORM_u_halo_blur varying lowp float halo_blur; #else uniform lowp float u_halo_blur; #endif + uniform sampler2D u_texture; uniform sampler2D u_fadetexture; uniform highp float u_gamma_scale; @@ -248,27 +263,32 @@ varying vec4 v_data0; varying vec2 v_data1; void main() { - + #ifdef HAS_UNIFORM_u_fill_color highp vec4 fill_color = u_fill_color; #endif + #ifdef HAS_UNIFORM_u_halo_color highp vec4 halo_color = u_halo_color; #endif + #ifdef HAS_UNIFORM_u_opacity lowp float opacity = u_opacity; #endif + #ifdef HAS_UNIFORM_u_halo_width lowp float halo_width = u_halo_width; #endif + #ifdef HAS_UNIFORM_u_halo_blur lowp float halo_blur = u_halo_blur; #endif + vec2 tex = v_data0.xy; vec2 fade_tex = v_data0.zw; float gamma_scale = v_data1.x; diff --git a/src/mbgl/sprite/sprite_loader.cpp b/src/mbgl/sprite/sprite_loader.cpp index 60ece5ed73..93d6dfd9ae 100644 --- a/src/mbgl/sprite/sprite_loader.cpp +++ b/src/mbgl/sprite/sprite_loader.cpp @@ -10,8 +10,8 @@ #include <mbgl/storage/file_source.hpp> #include <mbgl/storage/resource.hpp> #include <mbgl/storage/response.hpp> -#include <mbgl/util/run_loop.hpp> #include <mbgl/actor/actor.hpp> +#include <mbgl/actor/scheduler.hpp> #include <cassert> @@ -21,7 +21,7 @@ static SpriteLoaderObserver nullObserver; struct SpriteLoader::Loader { Loader(Scheduler& scheduler, SpriteLoader& imageManager) - : mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())), + : mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())), worker(scheduler, ActorRef<SpriteLoader>(imageManager, mailbox)) { } diff --git a/src/mbgl/storage/file_source_request.cpp b/src/mbgl/storage/file_source_request.cpp deleted file mode 100644 index 8a6fb21181..0000000000 --- a/src/mbgl/storage/file_source_request.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include <mbgl/storage/file_source_request.hpp> - -#include <mbgl/actor/mailbox.hpp> -#include <mbgl/util/run_loop.hpp> - -namespace mbgl { - -FileSourceRequest::FileSourceRequest(FileSource::Callback&& callback) - : responseCallback(callback) - , mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())) { -} - -FileSourceRequest::~FileSourceRequest() { - if (cancelCallback) { - cancelCallback(); - } - - mailbox->close(); -} - -void FileSourceRequest::onCancel(std::function<void()>&& callback) { - cancelCallback = std::move(callback); -} - -void FileSourceRequest::setResponse(const Response& response) { - // Copy, because calling the callback will sometimes self - // destroy this object. We cannot move because this method - // can be called more than one. - auto callback = responseCallback; - callback(response); -} - -ActorRef<FileSourceRequest> FileSourceRequest::actor() { - return ActorRef<FileSourceRequest>(*this, mailbox); -} - -} // namespace mbgl diff --git a/src/mbgl/storage/file_source_request.hpp b/src/mbgl/storage/file_source_request.hpp deleted file mode 100644 index 6bd0d44df6..0000000000 --- a/src/mbgl/storage/file_source_request.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include <mbgl/actor/actor_ref.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/util/async_request.hpp> - -#include <memory> -#include <functional> - -namespace mbgl { - -class Mailbox; - -class FileSourceRequest : public AsyncRequest { -public: - FileSourceRequest(FileSource::Callback&& callback); - ~FileSourceRequest() final; - - void onCancel(std::function<void()>&& callback); - void setResponse(const Response& res); - - ActorRef<FileSourceRequest> actor(); - -private: - FileSource::Callback responseCallback = nullptr; - std::function<void()> cancelCallback = nullptr; - - std::shared_ptr<Mailbox> mailbox; -}; - -} // namespace mbgl diff --git a/src/mbgl/storage/response.cpp b/src/mbgl/storage/response.cpp index a174339074..222f55db84 100644 --- a/src/mbgl/storage/response.cpp +++ b/src/mbgl/storage/response.cpp @@ -14,6 +14,7 @@ Response& Response::operator=(const Response& res) { error = res.error ? std::make_unique<Error>(*res.error) : nullptr; noContent = res.noContent; notModified = res.notModified; + mustRevalidate = res.mustRevalidate; data = res.data; modified = res.modified; expires = res.expires; 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/style.cpp b/src/mbgl/style/style.cpp index 5fe1ab4a06..bd8631fc52 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -34,20 +34,8 @@ std::string Style::getName() const { return impl->getName(); } -LatLng Style::getDefaultLatLng() const { - return impl->getDefaultLatLng(); -} - -double Style::getDefaultZoom() const { - return impl->getDefaultZoom(); -} - -double Style::getDefaultBearing() const { - return impl->getDefaultBearing(); -} - -double Style::getDefaultPitch() const { - return impl->getDefaultPitch(); +CameraOptions Style::getDefaultCamera() const { + return impl->getDefaultCamera(); } TransitionOptions Style::getTransitionOptions() const { diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index 604af4be20..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(); @@ -107,16 +107,18 @@ void Style::Impl::parse(const std::string& json_) { } name = parser.name; - defaultLatLng = parser.latLng; - defaultZoom = parser.zoom; - defaultBearing = parser.bearing; - defaultPitch = parser.pitch; + defaultCamera.center = parser.latLng; + defaultCamera.zoom = parser.zoom; + defaultCamera.angle = parser.bearing; + defaultCamera.pitch = parser.pitch; + setLight(std::make_unique<Light>(parser.light)); spriteLoaded = false; spriteLoader->load(parser.spriteURL, scheduler, fileSource); glyphURL = parser.glyphURL; + loaded = true; observer->onStyleLoaded(); } @@ -202,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); } @@ -212,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; @@ -232,20 +234,8 @@ std::string Style::Impl::getName() const { return name; } -LatLng Style::Impl::getDefaultLatLng() const { - return defaultLatLng; -} - -double Style::Impl::getDefaultZoom() const { - return defaultZoom; -} - -double Style::Impl::getDefaultBearing() const { - return defaultBearing; -} - -double Style::Impl::getDefaultPitch() const { - return defaultPitch; +CameraOptions Style::Impl::getDefaultCamera() const { + return defaultCamera; } std::vector<Source*> Style::Impl::getSources() { @@ -299,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) { @@ -329,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) { @@ -340,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/style_impl.hpp b/src/mbgl/style/style_impl.hpp index 76f244d5a4..3dc222bfad 100644 --- a/src/mbgl/style/style_impl.hpp +++ b/src/mbgl/style/style_impl.hpp @@ -12,6 +12,8 @@ #include <mbgl/style/layer.hpp> #include <mbgl/style/collection.hpp> +#include <mbgl/map/camera.hpp> + #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/optional.hpp> #include <mbgl/util/geo.hpp> @@ -69,10 +71,7 @@ public: std::unique_ptr<Layer> removeLayer(const std::string& layerID); std::string getName() const; - LatLng getDefaultLatLng() const; - double getDefaultZoom() const; - double getDefaultBearing() const; - double getDefaultPitch() const; + CameraOptions getDefaultCamera() const; TransitionOptions getTransitionOptions() const; void setTransitionOptions(const TransitionOptions&); @@ -117,10 +116,7 @@ private: // Defaults std::string name; - LatLng defaultLatLng; - double defaultZoom = 0; - double defaultBearing = 0; - double defaultPitch = 0; + CameraOptions defaultCamera; // SpriteLoaderObserver implementation. void onSpriteLoaded(std::vector<std::unique_ptr<Image>>&&) override; 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.hpp b/src/mbgl/text/glyph.hpp index 19ecdfd17c..6cccb72ebe 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -58,13 +58,13 @@ using GlyphMap = std::map<FontStack, Glyphs>; class PositionedGlyph { public: - explicit PositionedGlyph(GlyphID glyph_, float x_, float y_, float angle_) - : glyph(glyph_), x(x_), y(y_), angle(angle_) {} + explicit PositionedGlyph(GlyphID glyph_, float x_, float y_, bool vertical_) + : glyph(glyph_), x(x_), y(y_), vertical(vertical_) {} GlyphID glyph = 0; float x = 0; float y = 0; - float angle = 0; + bool vertical = false; }; enum class WritingModeType : uint8_t; 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/quads.cpp b/src/mbgl/text/quads.cpp index 7908ea4abc..0014ae8d01 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -133,18 +133,27 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, const float x2 = x1 + rect.w; const float y2 = y1 + rect.h; - const Point<float> center{builtInOffset.x - halfAdvance, static_cast<float>(static_cast<float>(glyph.metrics.advance) / 2.0)}; - Point<float> tl{x1, y1}; Point<float> tr{x2, y1}; Point<float> bl{x1, y2}; Point<float> br{x2, y2}; - if (positionedGlyph.angle != 0) { - tl = util::rotate(tl - center, positionedGlyph.angle) + center; - tr = util::rotate(tr - center, positionedGlyph.angle) + center; - bl = util::rotate(bl - center, positionedGlyph.angle) + center; - br = util::rotate(br - center, positionedGlyph.angle) + center; + if (alongLine && positionedGlyph.vertical) { + // Vertical-supporting glyphs are laid out in 24x24 point boxes (1 square em) + // In horizontal orientation, the y values for glyphs are below the midline + // and we use a "yOffset" of -17 to pull them up to the middle. + // By rotating counter-clockwise around the point at the center of the left + // edge of a 24x24 layout box centered below the midline, we align the center + // of the glyphs with the horizontal midline, so the yOffset is no longer + // necessary, but we also pull the glyph to the left along the x axis + const Point<float> center{-halfAdvance, halfAdvance}; + const float verticalRotation = -M_PI_2; + const Point<float> xOffsetCorrection{5, 0}; + + tl = util::rotate(tl - center, verticalRotation) + center + xOffsetCorrection; + tr = util::rotate(tr - center, verticalRotation) + center + xOffsetCorrection; + bl = util::rotate(bl - center, verticalRotation) + center + xOffsetCorrection; + br = util::rotate(br - center, verticalRotation) + center + xOffsetCorrection; } if (textRotate) { diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 4a206e9bae..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, @@ -237,10 +288,10 @@ void shapeLines(Shaping& shaping, const Glyph& glyph = **it->second; if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) { - shaping.positionedGlyphs.emplace_back(chr, x, y, 0); + shaping.positionedGlyphs.emplace_back(chr, x, y, false); x += glyph.metrics.advance + spacing; } else { - shaping.positionedGlyphs.emplace_back(chr, x, 0, -M_PI_2); + shaping.positionedGlyphs.emplace_back(chr, x, 0, true); x += verticalHeight + spacing; } } @@ -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 f6861140b7..ee4989462c 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -1,103 +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/util/string.hpp> - -#include <mapbox/geojsonvt.hpp> -#include <supercluster.hpp> +#include <mbgl/style/filter_evaluator.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, 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 33911df9ed..8c018ce3aa 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -17,10 +17,9 @@ #include <mbgl/geometry/feature_index.hpp> #include <mbgl/text/collision_tile.hpp> #include <mbgl/map/transform_state.hpp> -#include <mbgl/util/run_loop.hpp> #include <mbgl/style/filter_evaluator.hpp> -#include <mbgl/util/chrono.hpp> #include <mbgl/util/logging.hpp> +#include <mbgl/actor/scheduler.hpp> #include <iostream> @@ -28,12 +27,28 @@ 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) : Tile(id_), sourceID(std::move(sourceID_)), - mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())), + mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())), worker(parameters.workerScheduler, ActorRef<GeometryTile>(*this, mailbox), id_, @@ -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 c622d82e31..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,7 +216,10 @@ void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) { symbolDependenciesChanged(); } -void GeometryTileWorker::onImagesAvailable(ImageMap newImageMap) { +void GeometryTileWorker::onImagesAvailable(ImageMap newImageMap, uint64_t imageCorrelationID_) { + if (imageCorrelationID != imageCorrelationID_) { + return; // Ignore outdated image request replies. + } imageMap = std::move(newImageMap); pendingImageDependencies.clear(); symbolDependenciesChanged(); @@ -239,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)); } } @@ -354,8 +357,7 @@ void GeometryTileWorker::redoLayout() { std::move(buckets), std::move(featureIndex), *data ? (*data)->clone() : nullptr, - correlationID - }); + }, correlationID); attemptPlacement(); } @@ -419,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 1260fd1edd..2a3c9eeb0e 100644 --- a/src/mbgl/tile/raster_tile.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -8,7 +8,7 @@ #include <mbgl/storage/file_source.hpp> #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/renderer/buckets/raster_bucket.hpp> -#include <mbgl/util/run_loop.hpp> +#include <mbgl/actor/scheduler.hpp> namespace mbgl { @@ -17,7 +17,7 @@ RasterTile::RasterTile(const OverscaledTileID& id_, const Tileset& tileset) : Tile(id_), loader(*this, id_, parameters, tileset), - mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())), + mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())), worker(parameters.workerScheduler, ActorRef<RasterTile>(*this, mailbox)) { } @@ -29,7 +29,6 @@ void RasterTile::cancel() { void RasterTile::setError(std::exception_ptr err) { loaded = true; - renderable = false; observer->onTileError(*this, err); } @@ -38,20 +37,27 @@ void RasterTile::setData(std::shared_ptr<const std::string> data, optional<Timestamp> expires_) { modified = modified_; expires = expires_; - worker.invoke(&RasterTileWorker::parse, data); + + pending = true; + ++correlationID; + worker.invoke(&RasterTileWorker::parse, data, correlationID); } -void RasterTile::onParsed(std::unique_ptr<RasterBucket> result) { +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); } diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp index 28a27b2b37..2cb64e8ed7 100644 --- a/src/mbgl/tile/raster_tile.hpp +++ b/src/mbgl/tile/raster_tile.hpp @@ -36,8 +36,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 +45,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..7d7eb0b3fc 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -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..39cc0de8bd 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -23,7 +23,7 @@ class DebugBucket; class TransformState; class TileObserver; class PlacementConfig; -class RenderStyle; +class RenderLayer; class RenderedQueryOptions; class SourceQueryOptions; @@ -61,7 +61,7 @@ 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( diff --git a/src/mbgl/tile/tile_id.hpp b/src/mbgl/tile/tile_id.hpp deleted file mode 100644 index 811158e9b9..0000000000 --- a/src/mbgl/tile/tile_id.hpp +++ /dev/null @@ -1,276 +0,0 @@ -#pragma once - -#include <mbgl/util/constants.hpp> - -#include <cstdint> -#include <array> -#include <forward_list> -#include <algorithm> -#include <iosfwd> -#include <cassert> -#include <boost/functional/hash.hpp> - -namespace mbgl { - -class OverscaledTileID; -class CanonicalTileID; -class UnwrappedTileID; - -// Has integer z/x/y coordinates -// All tiles must be derived from 0/0/0 (=no tiles outside of the main tile pyramid) -// Used for requesting data; represents data tiles that exist out there. -// z is never larger than the source's maxzoom -class CanonicalTileID { -public: - CanonicalTileID(uint8_t z, uint32_t x, uint32_t y); - bool operator==(const CanonicalTileID&) const; - bool operator!=(const CanonicalTileID&) const; - bool operator<(const CanonicalTileID&) const; - bool isChildOf(const CanonicalTileID&) const; - CanonicalTileID scaledTo(uint8_t z) const; - std::array<CanonicalTileID, 4> children() const; - - const uint8_t z; - const uint32_t x; - const uint32_t y; -}; - -::std::ostream& operator<<(::std::ostream& os, const CanonicalTileID& rhs); -namespace util { -std::string toString(const CanonicalTileID&); -} // namespace util - -// Has integer z/x/y coordinates -// overscaledZ describes the zoom level this tile is intented to represent, e.g. when parsing data -// z is never larger than the source's maxzoom -// z/x/y describe the -class OverscaledTileID { -public: - OverscaledTileID(uint8_t overscaledZ, int16_t wrap, CanonicalTileID); - OverscaledTileID(uint8_t overscaledZ, int16_t wrap, uint8_t z, uint32_t x, uint32_t y); - OverscaledTileID(uint8_t z, uint32_t x, uint32_t y); - explicit OverscaledTileID(const CanonicalTileID&); - explicit OverscaledTileID(CanonicalTileID&&); - bool operator==(const OverscaledTileID&) const; - bool operator!=(const OverscaledTileID&) const; - bool operator<(const OverscaledTileID&) const; - bool isChildOf(const OverscaledTileID&) const; - uint32_t overscaleFactor() const; - OverscaledTileID scaledTo(uint8_t z) const; - UnwrappedTileID toUnwrapped() const; - - const uint8_t overscaledZ; - const int16_t wrap; - const CanonicalTileID canonical; -}; - -::std::ostream& operator<<(::std::ostream& os, const OverscaledTileID& rhs); -namespace util { -std::string toString(const OverscaledTileID&); -} // namespace util - -// Has integer z/x/y coordinates -// wrap describes tiles that are left/right of the main tile pyramid, e.g. when wrapping the world -// Used for describing what position tiles are getting rendered at (= calc the matrix) -// z is never larger than the source's maxzoom -class UnwrappedTileID { -public: - UnwrappedTileID(uint8_t z, int64_t x, int64_t y); - UnwrappedTileID(int16_t wrap, CanonicalTileID); - bool operator==(const UnwrappedTileID&) const; - bool operator!=(const UnwrappedTileID&) const; - bool operator<(const UnwrappedTileID&) const; - bool isChildOf(const UnwrappedTileID&) const; - std::array<UnwrappedTileID, 4> children() const; - OverscaledTileID overscaleTo(uint8_t z) const; - float pixelsToTileUnits(float pixelValue, float zoom) const; - - const int16_t wrap; - const CanonicalTileID canonical; -}; - -::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs); -namespace util { -std::string toString(const UnwrappedTileID&); -} // namespace util - -inline CanonicalTileID::CanonicalTileID(uint8_t z_, uint32_t x_, uint32_t y_) : z(z_), x(x_), y(y_) { - assert(z <= 32); - assert(x < (1ull << z)); - assert(y < (1ull << z)); -} - -inline bool CanonicalTileID::operator==(const CanonicalTileID& rhs) const { - return z == rhs.z && x == rhs.x && y == rhs.y; -} - -inline bool CanonicalTileID::operator!=(const CanonicalTileID& rhs) const { - return z != rhs.z || x != rhs.x || y != rhs.y; -} - -inline bool CanonicalTileID::operator<(const CanonicalTileID& rhs) const { - return std::tie(z, x, y) < std::tie(rhs.z, rhs.x, rhs.y); -} - -inline bool CanonicalTileID::isChildOf(const CanonicalTileID& parent) const { - // We're first testing for z == 0, to avoid a 32 bit shift, which is undefined. - return parent.z == 0 || - (parent.z < z && parent.x == (x >> (z - parent.z)) && parent.y == (y >> (z - parent.z))); -} - -inline CanonicalTileID CanonicalTileID::scaledTo(uint8_t targetZ) const { - if (targetZ <= z) { - return { targetZ, x >> (z - targetZ), y >> (z - targetZ) }; // parent or same - } else { - return { targetZ, x << (targetZ - z), y << (targetZ - z) }; // child - } -} - -inline std::array<CanonicalTileID, 4> CanonicalTileID::children() const { - const uint8_t childZ = z + 1; - const uint32_t childX = x * 2; - const uint32_t childY = y * 2; - return { { - { childZ, childX, childY }, - { childZ, childX, childY + 1 }, - { childZ, childX + 1, childY }, - { childZ, childX + 1, childY + 1 }, - } }; -} - -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, CanonicalTileID canonical_) - : overscaledZ(overscaledZ_), wrap(wrap_), canonical(std::move(canonical_)) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(overscaledZ_), wrap(wrap_), canonical(z, x, y) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(z), wrap(0), canonical(z, x, y) { -} - -inline OverscaledTileID::OverscaledTileID(const CanonicalTileID& canonical_) - : overscaledZ(canonical_.z), wrap(0), canonical(canonical_) { - assert(overscaledZ >= canonical.z); -} - -inline OverscaledTileID::OverscaledTileID(CanonicalTileID&& canonical_) - : overscaledZ(canonical_.z), wrap(0), canonical(std::forward<CanonicalTileID>(canonical_)) { - assert(overscaledZ >= canonical.z); -} - -inline bool OverscaledTileID::operator==(const OverscaledTileID& rhs) const { - return overscaledZ == rhs.overscaledZ && wrap == rhs.wrap &&canonical == rhs.canonical; -} - -inline bool OverscaledTileID::operator!=(const OverscaledTileID& rhs) const { - return overscaledZ != rhs.overscaledZ || wrap != rhs.wrap || canonical != rhs.canonical; -} - -inline bool OverscaledTileID::operator<(const OverscaledTileID& rhs) const { - return std::tie(overscaledZ, wrap, canonical) < std::tie(rhs.overscaledZ, rhs.wrap, rhs.canonical); -} - -inline uint32_t OverscaledTileID::overscaleFactor() const { - return 1u << (overscaledZ - canonical.z); -} - -inline bool OverscaledTileID::isChildOf(const OverscaledTileID& rhs) const { - return overscaledZ > rhs.overscaledZ && - (canonical == rhs.canonical || canonical.isChildOf(rhs.canonical)); -} - -inline OverscaledTileID OverscaledTileID::scaledTo(uint8_t z) const { - return { z, wrap, z >= canonical.z ? canonical : canonical.scaledTo(z) }; -} - -inline UnwrappedTileID OverscaledTileID::toUnwrapped() const { - return { wrap, canonical }; -} - -inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_) - : wrap((x_ < 0 ? x_ - (1ll << z_) + 1 : x_) / (1ll << z_)), - canonical( - z_, - static_cast<uint32_t>(x_ - wrap * (1ll << z_)), - y_ < 0 ? 0 : std::min(static_cast<uint32_t>(y_), static_cast<uint32_t>(1ull << z_) - 1)) { -} - -inline UnwrappedTileID::UnwrappedTileID(int16_t wrap_, CanonicalTileID canonical_) - : wrap(wrap_), canonical(std::move(canonical_)) { -} - -inline bool UnwrappedTileID::operator==(const UnwrappedTileID& rhs) const { - return wrap == rhs.wrap && canonical == rhs.canonical; -} - -inline bool UnwrappedTileID::operator!=(const UnwrappedTileID& rhs) const { - return wrap != rhs.wrap || canonical != rhs.canonical; -} - -inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const { - return std::tie(wrap, canonical) < std::tie(rhs.wrap, rhs.canonical); -} - -inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const { - return wrap == parent.wrap && canonical.isChildOf(parent.canonical); -} - -inline std::array<UnwrappedTileID, 4> UnwrappedTileID::children() const { - const uint8_t childZ = canonical.z + 1; - const uint32_t childX = canonical.x * 2; - const uint32_t childY = canonical.y * 2; - return { { - { wrap, { childZ, childX, childY } }, - { wrap, { childZ, childX, childY + 1 } }, - { wrap, { childZ, childX + 1, childY } }, - { wrap, { childZ, childX + 1, childY + 1 } }, - } }; -} - -inline OverscaledTileID UnwrappedTileID::overscaleTo(const uint8_t overscaledZ) const { - assert(overscaledZ >= canonical.z); - return { overscaledZ, wrap, canonical }; -} - -inline float UnwrappedTileID::pixelsToTileUnits(const float pixelValue, const float zoom) const { - return pixelValue * (util::EXTENT / (util::tileSize * std::pow(2, zoom - canonical.z))); -} - -} // namespace mbgl - -namespace std { - -template <> struct hash<mbgl::CanonicalTileID> { - size_t 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; - } -}; - -template <> struct hash<mbgl::UnwrappedTileID> { - size_t 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; - } -}; - -template <> struct hash<mbgl::OverscaledTileID> { - size_t 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_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_impl.hpp b/src/mbgl/tile/tile_loader_impl.hpp index 899cbaf9b0..598ec32c10 100644 --- a/src/mbgl/tile/tile_loader_impl.hpp +++ b/src/mbgl/tile/tile_loader_impl.hpp @@ -61,7 +61,10 @@ void TileLoader<T>::loadOptional() { // 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.priorModified = res.modified; resource.priorExpires = Timestamp{ Seconds::zero() }; + resource.priorEtag = res.etag; + resource.priorData = res.data; } else { loadedData(res); } 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/math.hpp b/src/mbgl/util/math.hpp index eb3c7d0fde..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; } @@ -112,7 +112,7 @@ inline T division(const T dividend, const T divisor, const T nan) { if (dividend == 0) { return nan; } else { - return std::copysign(std::numeric_limits<T>::infinity(), dividend); + return ::copysign(std::numeric_limits<T>::infinity(), dividend); } } else { return dividend / divisor; 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/thread.hpp b/src/mbgl/util/thread.hpp deleted file mode 100644 index 572f46080e..0000000000 --- a/src/mbgl/util/thread.hpp +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once - -#include <mbgl/actor/actor.hpp> -#include <mbgl/actor/mailbox.hpp> -#include <mbgl/actor/scheduler.hpp> -#include <mbgl/util/platform.hpp> -#include <mbgl/util/run_loop.hpp> -#include <mbgl/util/util.hpp> - -#include <cassert> -#include <future> -#include <memory> -#include <mutex> -#include <queue> -#include <string> -#include <thread> -#include <utility> - -namespace mbgl { -namespace util { - -// Manages a thread with `Object`. - -// Upon creation of this object, it launches a thread and creates an object of type `Object` -// in that thread. When the `Thread<>` object is destructed, the destructor waits -// for thread termination. The `Thread<>` constructor blocks until the thread and -// the `Object` are fully created, so after the object creation, it's safe to obtain the -// `Object` stored in this thread. The thread created will always have low priority on -// the platforms that support setting thread priority. -// -// The following properties make this class different from `ThreadPool`: -// -// - Only one thread is created. -// - `Object` will live in a single thread, providing thread affinity. -// - It is safe to use `ThreadLocal` in an `Object` managed by `Thread<>` -// - A `RunLoop` is created for the `Object` thread. -// - `Object` can use `Timer` and do asynchronous I/O, like wait for sockets events. -// -template<class Object> -class Thread : public Scheduler { -public: - template <class... Args> - Thread(const std::string& name, Args&&... args) { - std::promise<void> running; - - thread = std::thread([&] { - platform::setCurrentThreadName(name); - platform::makeThreadLowPriority(); - - util::RunLoop loop_(util::RunLoop::Type::New); - loop = &loop_; - - object = std::make_unique<Actor<Object>>(*this, std::forward<Args>(args)...); - running.set_value(); - - loop->run(); - loop = nullptr; - }); - - running.get_future().get(); - } - - ~Thread() override { - MBGL_VERIFY_THREAD(tid); - - if (paused) { - resume(); - } - - std::promise<void> joinable; - - // Kill the actor, so we don't get more - // messages posted on this scheduler after - // we delete the RunLoop. - loop->invoke([&] { - object.reset(); - joinable.set_value(); - }); - - joinable.get_future().get(); - - loop->stop(); - thread.join(); - } - - // Returns a non-owning reference to `Object` that - // can be used to send messages to `Object`. It is safe - // to the non-owning reference to outlive this object - // and be used after the `Thread<>` gets destroyed. - ActorRef<std::decay_t<Object>> actor() const { - return object->self(); - } - - // Pauses the `Object` thread. It will prevent the object to wake - // up from events such as timers and file descriptor I/O. Messages - // sent to a paused `Object` will be queued and only processed after - // `resume()` is called. - void pause() { - MBGL_VERIFY_THREAD(tid); - - assert(!paused); - - paused = std::make_unique<std::promise<void>>(); - resumed = std::make_unique<std::promise<void>>(); - - auto pausing = paused->get_future(); - - loop->invoke([this] { - auto resuming = resumed->get_future(); - paused->set_value(); - resuming.get(); - }); - - pausing.get(); - } - - // Resumes the `Object` thread previously paused by `pause()`. - void resume() { - MBGL_VERIFY_THREAD(tid); - - assert(paused); - - resumed->set_value(); - - resumed.reset(); - paused.reset(); - } - -private: - MBGL_STORE_THREAD(tid); - - void schedule(std::weak_ptr<Mailbox> mailbox) override { - { - std::lock_guard<std::mutex> lock(mutex); - queue.push(mailbox); - } - - loop->invoke([this] { receive(); }); - } - - void receive() { - std::unique_lock<std::mutex> lock(mutex); - - auto mailbox = queue.front(); - queue.pop(); - lock.unlock(); - - Mailbox::maybeReceive(mailbox); - } - - std::mutex mutex; - std::queue<std::weak_ptr<Mailbox>> queue; - std::thread thread; - std::unique_ptr<Actor<Object>> object; - - std::unique_ptr<std::promise<void>> paused; - std::unique_ptr<std::promise<void>> resumed; - - util::RunLoop* loop = nullptr; -}; - -} // namespace util -} // namespace mbgl diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp index b53e91162c..a5a1b1d70c 100644 --- a/src/mbgl/util/tile_cover.cpp +++ b/src/mbgl/util/tile_cover.cpp @@ -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..3c7a4ee44a 100644 --- a/src/mbgl/util/tile_cover.hpp +++ b/src/mbgl/util/tile_cover.hpp @@ -18,5 +18,8 @@ int32_t coveringZoomLevel(double z, 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 |