diff options
30 files changed, 688 insertions, 595 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index fb3a49c6f8..47a5d16a1b 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -184,6 +184,9 @@ set(MBGL_CORE_FILES src/mbgl/renderer/render_source.cpp src/mbgl/renderer/render_source.hpp src/mbgl/renderer/render_source_observer.hpp + src/mbgl/renderer/render_style.cpp + src/mbgl/renderer/render_style.hpp + src/mbgl/renderer/render_style_observer.hpp src/mbgl/renderer/render_tile.cpp src/mbgl/renderer/render_tile.hpp src/mbgl/renderer/style_diff.cpp diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index dce2914e7f..4618761273 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -59,7 +59,7 @@ std::map<UnwrappedTileID, RenderTile>& RenderAnnotationSource::getRenderTiles() std::unordered_map<std::string, std::vector<Feature>> RenderAnnotationSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, const RenderedQueryOptions& options) const { return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options); } diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp index ed30e62381..e0c9018e17 100644 --- a/src/mbgl/annotation/render_annotation_source.hpp +++ b/src/mbgl/annotation/render_annotation_source.hpp @@ -29,7 +29,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, 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 115b9f354d..b1594388c4 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -1,5 +1,5 @@ #include <mbgl/geometry/feature_index.hpp> -#include <mbgl/style/style.hpp> +#include <mbgl/renderer/render_style.hpp> #include <mbgl/renderer/render_layer.hpp> #include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/text/collision_tile.hpp> @@ -54,7 +54,7 @@ static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature& } static int16_t getAdditionalQueryRadius(const RenderedQueryOptions& queryOptions, - const style::Style& style, + const RenderStyle& style, const GeometryTile& tile, const float pixelsToTileUnits) { @@ -69,7 +69,7 @@ static int16_t getAdditionalQueryRadius(const RenderedQueryOptions& queryOptions if (queryOptions.layerIDs) { for (const auto& layerID : *queryOptions.layerIDs) { - RenderLayer* layer = style.getRenderLayer(layerID); + const RenderLayer* layer = style.getRenderLayer(layerID); if (layer) { getQueryRadius(*layer); } @@ -92,7 +92,7 @@ void FeatureIndex::query( const RenderedQueryOptions& queryOptions, const GeometryTileData& geometryTileData, const CanonicalTileID& tileID, - const style::Style& style, + const RenderStyle& style, const CollisionTile* collisionTile, const GeometryTile& tile) const { @@ -135,7 +135,7 @@ void FeatureIndex::addFeature( const RenderedQueryOptions& options, const GeometryTileData& geometryTileData, const CanonicalTileID& tileID, - const style::Style& style, + const RenderStyle& style, const float bearing, const float pixelsToTileUnits) const { diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp index f7aa0182e4..83f339a9de 100644 --- a/src/mbgl/geometry/feature_index.hpp +++ b/src/mbgl/geometry/feature_index.hpp @@ -13,10 +13,7 @@ namespace mbgl { class GeometryTile; class RenderedQueryOptions; - -namespace style { -class Style; -} // namespace style +class RenderStyle; class CollisionTile; class CanonicalTileID; @@ -45,7 +42,7 @@ public: const RenderedQueryOptions& options, const GeometryTileData&, const CanonicalTileID&, - const style::Style&, + const RenderStyle&, const CollisionTile*, const GeometryTile& tile) const; @@ -66,7 +63,7 @@ private: const RenderedQueryOptions& options, const GeometryTileData&, const CanonicalTileID&, - const style::Style&, + const RenderStyle&, const float bearing, const float pixelsToTileUnits) const; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 2fd575e6bf..dd3d10d253 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -15,6 +15,8 @@ #include <mbgl/renderer/update_parameters.hpp> #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/render_style.hpp> +#include <mbgl/renderer/render_style_observer.hpp> #include <mbgl/storage/file_source.hpp> #include <mbgl/storage/resource.hpp> #include <mbgl/storage/response.hpp> @@ -48,7 +50,8 @@ struct StillImageRequest { Map::StillImageCallback callback; }; -class Map::Impl : public style::Observer { +class Map::Impl : public style::Observer, + public RenderStyleObserver { public: Impl(Map&, Backend&, @@ -63,6 +66,7 @@ public: void onSourceChanged(style::Source&) override; void onUpdate(Update) override; + void onInvalidate() override; void onStyleLoaded() override; void onStyleError(std::exception_ptr) override; void onResourceError(std::exception_ptr) override; @@ -93,6 +97,7 @@ public: AnnotationManager annotationManager; std::unique_ptr<Painter> painter; std::unique_ptr<Style> style; + std::unique_ptr<RenderStyle> renderStyle; std::string styleURL; std::string styleJSON; @@ -169,6 +174,7 @@ Map::~Map() { // Explicit resets currently necessary because these abandon resources that need to be // cleaned up by context.reset(); + impl->renderStyle.reset(); impl->style.reset(); impl->painter.reset(); } @@ -238,16 +244,22 @@ void Map::Impl::render(View& view) { annotationManager.updateData(); } - style->update({ + renderStyle->update({ mode, - updateFlags, pixelRatio, debugOptions, timePoint, - transform.getState(), + style->getGlyphURL(), + style->spriteLoaded, + style->getTransitionOptions(), + style->getLight()->impl, + style->getImageImpls(), + style->getSourceImpls(), + style->getLayerImpls(), scheduler, fileSource, - annotationManager + annotationManager, + transform.getState() }); updateFlags = Update::Nothing; @@ -257,6 +269,8 @@ void Map::Impl::render(View& view) { painter = std::make_unique<Painter>(context, transform.getState(), pixelRatio, programCacheDir); } + bool loaded = style->isLoaded() && renderStyle->isLoaded(); + if (mode == MapMode::Continuous) { if (renderState == RenderState::Never) { observer.onWillStartRenderingMap(); @@ -272,15 +286,17 @@ void Map::Impl::render(View& view) { backend.updateAssumedState(); - painter->render(*style, + painter->render(*renderStyle, frameData, view); painter->cleanup(); - observer.onDidFinishRenderingFrame(style->isLoaded() ? MapObserver::RenderMode::Full : MapObserver::RenderMode::Partial); + observer.onDidFinishRenderingFrame(loaded + ? MapObserver::RenderMode::Full + : MapObserver::RenderMode::Partial); - if (!style->isLoaded()) { + if (!loaded) { renderState = RenderState::Partial; } else if (renderState != RenderState::Fully) { renderState = RenderState::Fully; @@ -293,10 +309,10 @@ void Map::Impl::render(View& view) { // Schedule an update if we need to paint another frame due to transitions or // animations that are still in progress - if (style->hasTransitions() || painter->needsAnimation() || transform.inTransition()) { + if (renderStyle->hasTransitions() || painter->needsAnimation() || transform.inTransition()) { onUpdate(Update::Repaint); } - } else if (stillImageRequest && style->isLoaded()) { + } else if (stillImageRequest && loaded) { FrameData frameData { timePoint, pixelRatio, mode, @@ -305,7 +321,7 @@ void Map::Impl::render(View& view) { backend.updateAssumedState(); - painter->render(*style, + painter->render(*renderStyle, frameData, view); @@ -333,6 +349,7 @@ void Map::setStyleURL(const std::string& url) { impl->styleMutated = false; impl->style = std::make_unique<Style>(impl->scheduler, impl->fileSource, impl->pixelRatio); + impl->renderStyle = std::make_unique<RenderStyle>(impl->scheduler, impl->fileSource); impl->styleRequest = impl->fileSource.request(Resource::style(impl->styleURL), [this](Response res) { // Once we get a fresh style, or the style is mutated, stop revalidating. @@ -379,12 +396,15 @@ void Map::setStyleJSON(const std::string& json) { impl->styleMutated = false; impl->style = std::make_unique<Style>(impl->scheduler, impl->fileSource, impl->pixelRatio); + impl->renderStyle = std::make_unique<RenderStyle>(impl->scheduler, impl->fileSource); impl->loadStyleJSON(json); } void Map::Impl::loadStyleJSON(const std::string& json) { style->setObserver(this); + renderStyle->setObserver(this); + style->setJSON(json); styleJSON = json; @@ -816,7 +836,7 @@ void Map::removeAnnotation(AnnotationID annotation) { std::vector<Feature> Map::queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options) { if (!impl->style) return {}; - return impl->style->queryRenderedFeatures( + return impl->renderStyle->queryRenderedFeatures( { point }, impl->transform.getState(), options @@ -826,7 +846,7 @@ std::vector<Feature> Map::queryRenderedFeatures(const ScreenCoordinate& point, c std::vector<Feature> Map::queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options) { if (!impl->style) return {}; - return impl->style->queryRenderedFeatures( + return impl->renderStyle->queryRenderedFeatures( { box.min, { box.max.x, box.min.y }, @@ -842,7 +862,7 @@ std::vector<Feature> Map::queryRenderedFeatures(const ScreenBox& box, const Rend std::vector<Feature> Map::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) { if (!impl->style) return {}; - const RenderSource* source = impl->style->getRenderSource(sourceID); + const RenderSource* source = impl->renderStyle->getRenderSource(sourceID); if (!source) return {}; return source->querySourceFeatures(options); @@ -1046,7 +1066,7 @@ MapDebugOptions Map::getDebug() const { } bool Map::isFullyLoaded() const { - return impl->style ? impl->style->isLoaded() : false; + return impl->style && impl->style->isLoaded() && impl->renderStyle->isLoaded(); } style::TransitionOptions Map::getTransitionOptions() const { @@ -1066,7 +1086,7 @@ void Map::setSourceTileCacheSize(size_t size) { if (size != impl->sourceCacheSize) { impl->sourceCacheSize = size; if (!impl->style) return; - impl->style->setSourceTileCacheSize(size); + impl->renderStyle->setSourceTileCacheSize(size); impl->backend.invalidate(); } } @@ -1076,8 +1096,8 @@ void Map::onLowMemory() { BackendScope guard(impl->backend); impl->painter->cleanup(); } - if (impl->style) { - impl->style->onLowMemory(); + if (impl->renderStyle) { + impl->renderStyle->onLowMemory(); impl->backend.invalidate(); } } @@ -1091,6 +1111,10 @@ void Map::Impl::onUpdate(Update flags) { asyncInvalidate.send(); } +void Map::Impl::onInvalidate() { + onUpdate(Update::Repaint); +} + void Map::Impl::onStyleLoaded() { observer.onDidFinishLoadingStyle(); } @@ -1111,6 +1135,7 @@ void Map::dumpDebugLogs() const { Log::Info(Event::General, "MapContext::styleURL: %s", impl->styleURL.c_str()); if (impl->style) { impl->style->dumpDebugLogs(); + impl->renderStyle->dumpDebugLogs(); } else { Log::Info(Event::General, "no style loaded"); } diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index a085f33c4b..6fb325db40 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -2,6 +2,7 @@ #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/render_style.hpp> #include <mbgl/style/source.hpp> #include <mbgl/style/source_impl.hpp> @@ -11,7 +12,6 @@ #include <mbgl/util/logging.hpp> #include <mbgl/gl/debugging.hpp> -#include <mbgl/style/style.hpp> #include <mbgl/style/layer_impl.hpp> #include <mbgl/style/layers/custom_layer_impl.hpp> @@ -126,7 +126,7 @@ void Painter::cleanup() { context.performCleanup(); } -void Painter::render(const Style& style, const FrameData& frame_, View& view) { +void Painter::render(RenderStyle& style, const FrameData& frame_, View& view) { frame = frame_; if (frame.contextMode == GLContextMode::Shared) { context.setDirtyState(); diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index e361b0f7d7..fddaff6318 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -7,6 +7,7 @@ #include <mbgl/renderer/frame_history.hpp> #include <mbgl/renderer/render_item.hpp> #include <mbgl/renderer/bucket.hpp> +#include <mbgl/renderer/render_light.hpp> #include <mbgl/gl/context.hpp> #include <mbgl/programs/debug_program.hpp> @@ -15,8 +16,6 @@ #include <mbgl/programs/extrusion_texture_program.hpp> #include <mbgl/programs/raster_program.hpp> -#include <mbgl/style/style.hpp> - #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/chrono.hpp> #include <mbgl/util/constants.hpp> @@ -29,6 +28,7 @@ namespace mbgl { +class RenderStyle; class RenderTile; class SpriteAtlas; class View; @@ -59,11 +59,6 @@ class TilePyramid; struct ClipID; -namespace style { -class Style; -class Source; -} // namespace style - struct FrameData { TimePoint timePoint; float pixelRatio; @@ -77,7 +72,7 @@ public: Painter(gl::Context&, const TransformState&, float pixelRatio, const std::string& programCacheDir); ~Painter(); - void render(const style::Style&, + void render(RenderStyle&, const FrameData&, View&); diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index b229d8a0bd..b396a0fdb6 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -18,6 +18,7 @@ namespace mbgl { class Painter; class TransformState; class RenderTile; +class RenderStyle; class RenderLayer; class RenderedQueryOptions; class SourceQueryOptions; @@ -25,10 +26,6 @@ class Tile; class RenderSourceObserver; class TileParameters; -namespace style { -class Style; -} // namespace style - namespace algorithm { class ClipIDGenerator; } // namespace algorithm @@ -72,7 +69,7 @@ public: virtual std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, const RenderedQueryOptions& options) const = 0; virtual std::vector<Feature> diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp new file mode 100644 index 0000000000..a3a7d57527 --- /dev/null +++ b/src/mbgl/renderer/render_style.cpp @@ -0,0 +1,445 @@ +#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/style_diff.hpp> +#include <mbgl/style/style.hpp> +#include <mbgl/style/source_impl.hpp> +#include <mbgl/style/transition_options.hpp> +#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/sprite/sprite_loader.hpp> +#include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/geometry/line_atlas.hpp> +#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/map/query.hpp> +#include <mbgl/tile/tile.hpp> +#include <mbgl/util/math.hpp> +#include <mbgl/util/string.hpp> + +namespace mbgl { + +using namespace style; + +RenderStyleObserver nullObserver; + +RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_) + : scheduler(scheduler_), + fileSource(fileSource_), + glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)), + spriteAtlas(std::make_unique<SpriteAtlas>()), + lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })), + renderLight(makeMutable<Light::Impl>()), + observer(&nullObserver) { + glyphAtlas->setObserver(this); +} + +RenderStyle::~RenderStyle() = default; + +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) { + const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint); + + const TransitionParameters transitionParameters { + parameters.mode == MapMode::Continuous ? parameters.timePoint : Clock::time_point::max(), + parameters.mode == MapMode::Continuous ? parameters.transitionOptions : TransitionOptions() + }; + + const PropertyEvaluationParameters evaluationParameters { + zoomHistory, + parameters.mode == MapMode::Continuous ? parameters.timePoint : Clock::time_point::max(), + parameters.mode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Duration::zero() + }; + + const TileParameters tileParameters { + parameters.pixelRatio, + parameters.debugOptions, + parameters.transformState, + parameters.scheduler, + parameters.fileSource, + parameters.mode, + parameters.annotationManager, + *spriteAtlas, + *glyphAtlas + }; + + glyphAtlas->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) { + spriteAtlas->removeImage(entry.first); + } + + // Add added images to sprite atlas. + for (const auto& entry : imageDiff.added) { + spriteAtlas->addImage(entry.second); + } + + // Update changed images. + for (const auto& entry : imageDiff.changed) { + spriteAtlas->updateImage(entry.second[1]); + } + + if (parameters.spriteLoaded && !spriteAtlas->isLoaded()) { + spriteAtlas->onSpriteLoaded(); + } + + + 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[1]); + } + + // 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 (getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) { + needsRendering = true; + } + + if (hasLayoutDifference(layerDiff, layer->id)) { + 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 (!spriteAtlas->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[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; + } + + auto& renderTiles = source->getRenderTiles(); + const bool symbolLayer = layer->is<RenderSymbolLayer>(); + + // 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::vector<std::reference_wrapper<RenderTile>> sortedTiles; + std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles), + [](auto& pair) { return std::ref(pair.second); }); + if (symbolLayer) { + 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); + }); + } + + 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::setSourceTileCacheSize(size_t size) { + for (const auto& entry : renderSources) { + entry.second->setCacheSize(size); + } +} + +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(); + } + + spriteAtlas->dumpDebugLogs(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_style.hpp b/src/mbgl/renderer/render_style.hpp new file mode 100644 index 0000000000..ff03b48fdf --- /dev/null +++ b/src/mbgl/renderer/render_style.hpp @@ -0,0 +1,93 @@ +#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_atlas_observer.hpp> +#include <mbgl/map/zoom_history.hpp> +#include <mbgl/map/mode.hpp> + +#include <memory> +#include <string> +#include <vector> + +namespace mbgl { + +class FileSource; +class GlyphAtlas; +class SpriteAtlas; +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 GlyphAtlasObserver, + 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 setSourceTileCacheSize(size_t); + void onLowMemory(); + + void dumpDebugLogs() const; + + Scheduler& scheduler; + FileSource& fileSource; + std::unique_ptr<GlyphAtlas> glyphAtlas; + std::unique_ptr<SpriteAtlas> spriteAtlas; + std::unique_ptr<LineAtlas> lineAtlas; + +private: + std::vector<Immutable<style::Image::Impl>> imageImpls; + std::vector<Immutable<style::Source::Impl>> sourceImpls; + 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; + + // GlyphAtlasObserver 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 new file mode 100644 index 0000000000..5852dd68b8 --- /dev/null +++ b/src/mbgl/renderer/render_style_observer.hpp @@ -0,0 +1,14 @@ +#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/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 19e93ca2ba..96500d8fae 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -74,7 +74,7 @@ std::map<UnwrappedTileID, RenderTile>& RenderGeoJSONSource::getRenderTiles() { std::unordered_map<std::string, std::vector<Feature>> RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, const RenderedQueryOptions& options) const { return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options); } diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp index c3783af642..2683ef9d21 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -33,7 +33,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, 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 5f9887cdb8..ffa8e6bb5e 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -57,7 +57,7 @@ void RenderImageSource::finishRender(Painter& painter) { std::unordered_map<std::string, std::vector<Feature>> RenderImageSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, - const style::Style&, + const RenderStyle&, const RenderedQueryOptions&) const { return {}; } diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index dc5c32876b..c4685cf891 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -43,7 +43,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, 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 239bac9dd6..81a9771676 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -71,7 +71,7 @@ std::map<UnwrappedTileID, RenderTile>& RenderRasterSource::getRenderTiles() { std::unordered_map<std::string, std::vector<Feature>> RenderRasterSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, - const style::Style&, + const RenderStyle&, const RenderedQueryOptions&) const { return {}; } diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp index cbe16b967e..9209a5ca65 100644 --- a/src/mbgl/renderer/sources/render_raster_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -29,7 +29,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, 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 869d87b0b7..30014a89dc 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -75,7 +75,7 @@ std::map<UnwrappedTileID, RenderTile>& RenderVectorSource::getRenderTiles() { std::unordered_map<std::string, std::vector<Feature>> RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, const RenderedQueryOptions& options) const { return tilePyramid.queryRenderedFeatures(geometry, transformState, style, options); } diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp index c1357141a6..1f1acdd551 100644 --- a/src/mbgl/renderer/sources/render_vector_source.hpp +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -29,7 +29,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, 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 7d9d7c88ca..184bafc204 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -186,7 +186,7 @@ void TilePyramid::removeStaleTiles(const std::set<OverscaledTileID>& retain) { std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, const RenderedQueryOptions& options) const { std::unordered_map<std::string, std::vector<Feature>> result; if (renderTiles.empty() || geometry.empty()) { diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index b99c94d065..d989306414 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -21,14 +21,11 @@ namespace mbgl { class Painter; class TransformState; class RenderTile; +class RenderStyle; class RenderedQueryOptions; class SourceQueryOptions; class TileParameters; -namespace style { -class Style; -} // namespace style - class TilePyramid { public: TilePyramid(); @@ -55,7 +52,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, const RenderedQueryOptions& options) const; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const; diff --git a/src/mbgl/renderer/update_parameters.hpp b/src/mbgl/renderer/update_parameters.hpp index ae54ac09e7..6e78acfa07 100644 --- a/src/mbgl/renderer/update_parameters.hpp +++ b/src/mbgl/renderer/update_parameters.hpp @@ -13,14 +13,22 @@ class AnnotationManager; class UpdateParameters { public: const MapMode mode; - const Update updateFlags; const float pixelRatio; const MapDebugOptions debugOptions; const TimePoint timePoint; - const TransformState& transformState; + + const std::string glyphURL; + const bool spriteLoaded; + const style::TransitionOptions transitionOptions; + const Immutable<style::Light::Impl> light; + const std::vector<Immutable<style::Image::Impl>> images; + const std::vector<Immutable<style::Source::Impl>> sources; + const std::vector<Immutable<style::Layer::Impl>> layers; + Scheduler& scheduler; FileSource& fileSource; AnnotationManager& annotationManager; + const TransformState& transformState; }; } // namespace mbgl diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 98d774f974..34e1cdeb6f 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -15,39 +15,10 @@ #include <mbgl/style/layer_impl.hpp> #include <mbgl/style/parser.hpp> #include <mbgl/style/transition_options.hpp> -#include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/sprite/sprite_loader.hpp> -#include <mbgl/text/glyph_atlas.hpp> -#include <mbgl/geometry/line_atlas.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/style_diff.hpp> -#include <mbgl/sprite/sprite_atlas.hpp> -#include <mbgl/tile/tile.hpp> -#include <mbgl/util/constants.hpp> #include <mbgl/util/exception.hpp> -#include <mbgl/util/geometry.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/logging.hpp> -#include <mbgl/util/math.hpp> -#include <mbgl/util/std.hpp> -#include <mbgl/math/minmax.hpp> -#include <mbgl/map/query.hpp> - -#include <algorithm> namespace mbgl { namespace style { @@ -57,14 +28,9 @@ static Observer nullObserver; Style::Style(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio) : scheduler(scheduler_), fileSource(fileSource_), - glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)), spriteLoader(std::make_unique<SpriteLoader>(pixelRatio)), - spriteAtlas(std::make_unique<SpriteAtlas>()), - lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })), light(std::make_unique<Light>()), - renderLight(light->impl), observer(&nullObserver) { - glyphAtlas->setObserver(this); spriteLoader->setObserver(this); light->setObserver(this); } @@ -87,7 +53,6 @@ TransitionOptions Style::getTransitionOptions() const { void Style::setJSON(const std::string& json) { sources.clear(); - renderSources.clear(); layers.clear(); transitionOptions = {}; @@ -117,8 +82,8 @@ void Style::setJSON(const std::string& json) { defaultPitch = parser.pitch; setLight(std::make_unique<Light>(parser.light)); - glyphAtlas->setURL(parser.glyphURL); spriteLoader->load(parser.spriteURL, scheduler, fileSource); + glyphURL = parser.glyphURL; loaded = true; @@ -181,15 +146,6 @@ std::unique_ptr<Source> Style::removeSource(const std::string& id) { return source; } -std::vector<const Layer*> Style::getLayers() const { - std::vector<const Layer*> result; - result.reserve(layers.size()); - for (const auto& layer : layers) { - result.push_back(layer.get()); - } - return result; -} - std::vector<Layer*> Style::getLayers() { std::vector<Layer*> result; result.reserve(layers.size()); @@ -250,29 +206,6 @@ std::unique_ptr<Layer> Style::removeLayer(const std::string& id) { return layer; } -std::vector<const RenderLayer*> Style::getRenderLayers() const { - std::vector<const RenderLayer*> result; - result.reserve(renderLayers.size()); - for (const auto& entry : renderLayers) { - result.push_back(entry.second.get()); - } - return result; -} - -std::vector<RenderLayer*> Style::getRenderLayers() { - std::vector<RenderLayer*> result; - result.reserve(renderLayers.size()); - for (auto& entry : renderLayers) { - result.push_back(entry.second.get()); - } - return result; -} - -RenderLayer* Style::getRenderLayer(const std::string& id) const { - auto it = renderLayers.find(id); - return it != renderLayers.end() ? it->second.get() : nullptr; -} - void Style::setLight(std::unique_ptr<Light> light_) { light = std::move(light_); light->setObserver(this); @@ -283,10 +216,6 @@ Light* Style::getLight() const { return light.get(); } -const RenderLight& Style::getRenderLight() const { - return renderLight; -} - std::string Style::getName() const { return name; } @@ -307,177 +236,6 @@ double Style::getDefaultPitch() const { return defaultPitch; } -void Style::update(const UpdateParameters& parameters) { - const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint); - - const TransitionParameters transitionParameters { - parameters.mode == MapMode::Continuous ? parameters.timePoint : Clock::time_point::max(), - parameters.mode == MapMode::Continuous ? transitionOptions : TransitionOptions() - }; - - const PropertyEvaluationParameters evaluationParameters { - zoomHistory, - parameters.mode == MapMode::Continuous ? parameters.timePoint : Clock::time_point::max(), - parameters.mode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Duration::zero() - }; - - const TileParameters tileParameters { - parameters.pixelRatio, - parameters.debugOptions, - parameters.transformState, - parameters.scheduler, - parameters.fileSource, - parameters.mode, - parameters.annotationManager, - *spriteAtlas, - *glyphAtlas - }; - - // Update light. - const bool lightChanged = renderLight.impl != light->impl; - - if (lightChanged) { - renderLight.impl = light->impl; - renderLight.transition(transitionParameters); - } - - if (lightChanged || zoomChanged || renderLight.hasTransition()) { - renderLight.evaluate(evaluationParameters); - } - - - std::vector<Immutable<Image::Impl>> newImageImpls; - newImageImpls.reserve(images.size()); - for (const auto& entry : images) { - newImageImpls.push_back(entry.second->impl); - } - - const ImageDifference imageDiff = diffImages(imageImpls, newImageImpls); - imageImpls = std::move(newImageImpls); - - // Remove removed images from sprite atlas. - for (const auto& entry : imageDiff.removed) { - spriteAtlas->removeImage(entry.first); - } - - // Add added images to sprite atlas. - for (const auto& entry : imageDiff.added) { - spriteAtlas->addImage(entry.second); - } - - // Update changed images. - for (const auto& entry : imageDiff.changed) { - spriteAtlas->updateImage(entry.second[1]); - } - - if (spriteLoaded && !spriteAtlas->isLoaded()) { - spriteAtlas->onSpriteLoaded(); - } - - - std::vector<Immutable<Source::Impl>> newSourceImpls; - newSourceImpls.reserve(sources.size()); - for (const auto& source : sources) { - newSourceImpls.push_back(source->baseImpl); - } - - - std::vector<Immutable<Layer::Impl>> newLayerImpls; - newLayerImpls.reserve(layers.size()); - for (const auto& layer : layers) { - newLayerImpls.push_back(layer->baseImpl); - } - - const LayerDifference layerDiff = diffLayers(layerImpls, newLayerImpls); - layerImpls = std::move(newLayerImpls); - - // 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[1]); - } - - // 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, newSourceImpls); - sourceImpls = std::move(newSourceImpls); - - // 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 (getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) { - needsRendering = true; - } - - if (hasLayoutDifference(layerDiff, layer->id)) { - needsRelayout = true; - } - - filteredLayers.push_back(layer); - } - - renderSources.at(source->id)->update(source, - filteredLayers, - needsRendering, - needsRelayout, - tileParameters); - } -} - -std::vector<const Source*> Style::getSources() const { - std::vector<const Source*> result; - result.reserve(sources.size()); - for (const auto& source : sources) { - result.push_back(source.get()); - } - return result; -} - std::vector<Source*> Style::getSources() { std::vector<Source*> result; result.reserve(sources.size()); @@ -495,25 +253,6 @@ Source* Style::getSource(const std::string& id) const { return it != sources.end() ? it->get() : nullptr; } -RenderSource* Style::getRenderSource(const std::string& id) const { - auto it = renderSources.find(id); - return it != renderSources.end() ? it->second.get() : nullptr; -} - -bool Style::hasTransitions() const { - if (renderLight.hasTransition()) { - return true; - } - - for (const auto& entry : renderLayers) { - if (entry.second->hasTransition()) { - return true; - } - } - - return false; -} - bool Style::isLoaded() const { if (!loaded) { return false; @@ -529,12 +268,6 @@ bool Style::isLoaded() const { } } - for (const auto& entry: renderSources) { - if (!entry.second->isLoaded()) { - return false; - } - } - return true; } @@ -557,182 +290,10 @@ const style::Image* Style::getImage(const std::string& id) const { return it == images.end() ? nullptr : it->second.get(); } -RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const { - 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[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; - } - - auto& renderTiles = source->getRenderTiles(); - const bool symbolLayer = layer->is<RenderSymbolLayer>(); - - // 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::vector<std::reference_wrapper<RenderTile>> sortedTiles; - std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles), - [](auto& pair) { return std::ref(pair.second); }); - if (symbolLayer) { - 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); - }); - } - - 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> Style::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 (Layer* layer = getLayer(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 Style::setSourceTileCacheSize(size_t size) { - for (const auto& entry : renderSources) { - entry.second->setCacheSize(size); - } -} - -void Style::onLowMemory() { - for (const auto& entry : renderSources) { - entry.second->onLowMemory(); - } -} - void Style::setObserver(style::Observer* observer_) { observer = observer_; } -void Style::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) { - lastError = 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 Style::onSourceLoaded(Source& source) { observer->onSourceLoaded(source); observer->onUpdate(Update::Repaint); @@ -757,17 +318,6 @@ void Style::onSourceDescriptionChanged(Source& source) { } } -void Style::onTileChanged(RenderSource&, const OverscaledTileID&) { - observer->onUpdate(Update::Repaint); -} - -void Style::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) { - lastError = 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 Style::onSpriteLoaded(std::vector<std::unique_ptr<Image>>&& images_) { for (auto& image : images_) { addImage(std::move(image)); @@ -794,12 +344,37 @@ void Style::dumpDebugLogs() const { for (const auto& source : sources) { source->dumpDebugLogs(); } +} + +const std::string& Style::getGlyphURL() const { + return glyphURL; +} + +std::vector<Immutable<Image::Impl>> Style::getImageImpls() const { + std::vector<Immutable<style::Image::Impl>> result; + result.reserve(images.size()); + for (const auto& image : images) { + result.push_back(image.second->impl); + } + return result; +} - for (const auto& entry : renderSources) { - entry.second->dumpDebugLogs(); +std::vector<Immutable<Source::Impl>> Style::getSourceImpls() const { + std::vector<Immutable<style::Source::Impl>> result; + result.reserve(sources.size()); + for (const auto& source : sources) { + result.push_back(source->baseImpl); } + return result; +} - spriteAtlas->dumpDebugLogs(); +std::vector<Immutable<Layer::Impl>> Style::getLayerImpls() const { + std::vector<Immutable<style::Layer::Impl>> result; + result.reserve(layers.size()); + for (const auto& layer : layers) { + result.push_back(layer->baseImpl); + } + return result; } } // namespace style diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index a947fce44f..a60fee9264 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -5,49 +5,30 @@ #include <mbgl/style/source_observer.hpp> #include <mbgl/style/layer_observer.hpp> #include <mbgl/style/light_observer.hpp> -#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_atlas_observer.hpp> #include <mbgl/sprite/sprite_loader_observer.hpp> -#include <mbgl/map/mode.hpp> -#include <mbgl/map/zoom_history.hpp> +#include <mbgl/style/image.hpp> +#include <mbgl/style/source.hpp> +#include <mbgl/style/layer.hpp> #include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/chrono.hpp> #include <mbgl/util/optional.hpp> -#include <mbgl/util/feature.hpp> #include <mbgl/util/geo.hpp> -#include <cstdint> #include <memory> #include <string> #include <vector> +#include <unordered_map> namespace mbgl { +class Scheduler; class FileSource; -class GlyphAtlas; -class SpriteAtlas; class SpriteLoader; -class LineAtlas; -class RenderData; -class TransformState; -class RenderedQueryOptions; -class Scheduler; -class UpdateParameters; namespace style { -class Layer; -class QueryParameters; - -class Style : public GlyphAtlasObserver, - public SpriteLoaderObserver, +class Style : public SpriteLoaderObserver, public SourceObserver, - public RenderSourceObserver, public LayerObserver, public LightObserver, public util::noncopyable { @@ -61,32 +42,21 @@ public: bool isLoaded() const; - void update(const UpdateParameters&); - - bool hasTransitions() const; - std::exception_ptr getLastError() const { return lastError; } - std::vector<const Source*> getSources() const; std::vector<Source*> getSources(); Source* getSource(const std::string& id) const; void addSource(std::unique_ptr<Source>); std::unique_ptr<Source> removeSource(const std::string& sourceID); - std::vector<const Layer*> getLayers() const; std::vector<Layer*> getLayers(); Layer* getLayer(const std::string& id) const; Layer* addLayer(std::unique_ptr<Layer>, optional<std::string> beforeLayerID = {}); std::unique_ptr<Layer> removeLayer(const std::string& layerID); - // Should be moved to Impl eventually - std::vector<const RenderLayer*> getRenderLayers() const; - std::vector<RenderLayer*> getRenderLayers(); - RenderLayer* getRenderLayer(const std::string& id) const; - std::string getName() const; LatLng getDefaultLatLng() const; double getDefaultZoom() const; @@ -98,33 +68,28 @@ public: void setLight(std::unique_ptr<Light>); Light* getLight() const; - const RenderLight& getRenderLight() const; const style::Image* getImage(const std::string&) const; void addImage(std::unique_ptr<style::Image>); void removeImage(const std::string&); - RenderData getRenderData(MapDebugOptions, float angle) const; - - std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry, - const TransformState& transformState, - const RenderedQueryOptions& options) const; + const std::string& getGlyphURL() const; - void setSourceTileCacheSize(size_t); - void onLowMemory(); + std::vector<Immutable<Image::Impl>> getImageImpls() const; + std::vector<Immutable<Source::Impl>> getSourceImpls() const; + std::vector<Immutable<Layer::Impl>> getLayerImpls() const; void dumpDebugLogs() const; + bool loaded = false; + bool spriteLoaded = false; + +private: Scheduler& scheduler; FileSource& fileSource; - std::unique_ptr<GlyphAtlas> glyphAtlas; std::unique_ptr<SpriteLoader> spriteLoader; - std::unique_ptr<SpriteAtlas> spriteAtlas; - std::unique_ptr<LineAtlas> lineAtlas; - - RenderSource* getRenderSource(const std::string& id) const; + std::string glyphURL; -private: std::unordered_map<std::string, std::unique_ptr<style::Image>> images; std::vector<std::unique_ptr<Source>> sources; std::vector<std::unique_ptr<Layer>> layers; @@ -138,19 +103,8 @@ private: double defaultBearing = 0; double defaultPitch = 0; - std::vector<Immutable<Image::Impl>> imageImpls; - std::vector<Immutable<Source::Impl>> sourceImpls; - std::vector<Immutable<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; - std::vector<std::unique_ptr<Layer>>::const_iterator findLayer(const std::string& layerID) const; - // GlyphAtlasObserver implementation. - void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override; - // SpriteLoaderObserver implementation. void onSpriteLoaded(std::vector<std::unique_ptr<Image>>&&) override; void onSpriteError(std::exception_ptr) override; @@ -160,8 +114,6 @@ private: void onSourceChanged(Source&) override; void onSourceError(Source&, std::exception_ptr) override; void onSourceDescriptionChanged(Source&) override; - void onTileChanged(RenderSource&, const OverscaledTileID&) override; - void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override; // LayerObserver implementation. void onLayerChanged(Layer&) override; @@ -173,12 +125,6 @@ private: Observer* observer = &nullObserver; std::exception_ptr lastError; - - ZoomHistory zoomHistory; - bool spriteLoaded = false; - -public: - bool loaded = false; }; } // namespace style diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 1a60549eb0..32fb6148c2 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -176,7 +176,7 @@ void GeometryTile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState& transformState, - const style::Style& style, + const RenderStyle& style, const RenderedQueryOptions& options) { if (!featureIndex || !data) return; diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 7fd8d8bc77..c6d0bb35ec 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -19,6 +19,7 @@ namespace mbgl { class GeometryTileData; class FeatureIndex; class CollisionTile; +class RenderStyle; class RenderLayer; class SourceQueryOptions; class TileParameters; @@ -49,7 +50,7 @@ public: std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, - const style::Style&, + const RenderStyle&, const RenderedQueryOptions& options) override; void querySourceFeatures( diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index ec8fe66eec..5080d42933 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 style::Style&, + const RenderStyle&, const RenderedQueryOptions&) {} void Tile::querySourceFeatures( diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index 91ed4aadaa..bddae5138b 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -22,13 +22,10 @@ class DebugBucket; class TransformState; class TileObserver; class PlacementConfig; +class RenderStyle; class RenderedQueryOptions; class SourceQueryOptions; -namespace style { -class Style; -} // namespace style - class Tile : private util::noncopyable { public: Tile(OverscaledTileID); @@ -57,7 +54,7 @@ public: std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, - const style::Style&, + const RenderStyle&, const RenderedQueryOptions& options); virtual void querySourceFeatures( diff --git a/test/tile/annotation_tile.test.cpp b/test/tile/annotation_tile.test.cpp index bfd991c504..927799b26d 100644 --- a/test/tile/annotation_tile.test.cpp +++ b/test/tile/annotation_tile.test.cpp @@ -5,7 +5,7 @@ #include <mbgl/util/run_loop.hpp> #include <mbgl/map/transform.hpp> #include <mbgl/map/query.hpp> -#include <mbgl/style/style.hpp> +#include <mbgl/renderer/render_style.hpp> #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/map/query.hpp> #include <mbgl/text/collision_tile.hpp> @@ -26,7 +26,7 @@ public: util::RunLoop loop; ThreadPool threadPool { 1 }; AnnotationManager annotationManager; - style::Style style { threadPool, fileSource, 1.0 }; + RenderStyle style { threadPool, fileSource }; SpriteAtlas spriteAtlas; GlyphAtlas glyphAtlas { { 512, 512, }, fileSource }; |