diff options
-rw-r--r-- | cmake/core-files.cmake | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/paint_parameters.cpp | 13 | ||||
-rw-r--r-- | src/mbgl/renderer/paint_parameters.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/renderer/render_style.cpp | 453 | ||||
-rw-r--r-- | src/mbgl/renderer/render_style.hpp | 92 | ||||
-rw-r--r-- | src/mbgl/renderer/render_style_observer.hpp | 14 | ||||
-rw-r--r-- | src/mbgl/renderer/renderer_impl.cpp | 438 | ||||
-rw-r--r-- | src/mbgl/renderer/renderer_impl.hpp | 65 |
8 files changed, 477 insertions, 608 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 1a86da6f24..27af6e59f9 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -194,9 +194,6 @@ set(MBGL_CORE_FILES src/mbgl/renderer/render_source_observer.hpp src/mbgl/renderer/render_static_data.cpp src/mbgl/renderer/render_static_data.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/renderer.cpp diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index ebdaecd3a3..584dcdf118 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_), diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index e9d3562a75..eb1ad73ad5 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; diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp deleted file mode 100644 index 77516586d6..0000000000 --- a/src/mbgl/renderer/render_style.cpp +++ /dev/null @@ -1,453 +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::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; -} - -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/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index dd3c0d41a1..ae21c35152 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -1,13 +1,37 @@ #include <mbgl/renderer/renderer_impl.hpp> -#include <mbgl/renderer/render_style.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_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/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/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/tile/tile.hpp> +#include <mbgl/util/math.hpp> +#include <mbgl/util/string.hpp> +#include <mbgl/util/logging.hpp> namespace mbgl { @@ -24,19 +48,30 @@ 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(); + glyphManager.reset(); + imageManager.reset(); + lineAtlas.reset(); + renderSources.reset(); + renderLayers.reset(); staticData.reset(); }; @@ -50,7 +85,152 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { assert(BackendScope::exists()); - renderStyle->update(updateParameters); + 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, + updateParameters.scheduler, + updateParameters.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)); + } + + // 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); + } + transformState = updateParameters.transformState; if (!staticData) { @@ -63,12 +243,14 @@ 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::Continuous) { if (renderState == RenderState::Never) { @@ -84,7 +266,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { observer->onDidFinishRenderingFrame( loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial, - renderStyle->hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION) + hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION) ); if (!loaded) { @@ -114,10 +296,109 @@ void Renderer::Impl::doRender(PaintParameters& parameters) { parameters.context.setDirtyState(); } - RenderData renderData = renderStyle->getRenderData(parameters.debugOptions, parameters.state.getAngle()); + RenderData renderData; const std::vector<RenderItem>& order = renderData.order; const std::unordered_set<RenderSource*>& sources = renderData.sources; + for (const auto& entry : renderSources) { + if (entry.second->isEnabled()) { + renderData.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 (parameters.debugOptions & MapDebugOptions::Overdraw) { + // We want to skip glClear optimization in overdraw mode. + renderData.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(). + renderData.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. + renderData.order.emplace_back(*layer, nullptr); + } + continue; + } + + if (layer->is<RenderCustomLayer>()) { + renderData.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(), [&](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, 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)); + renderData.order.emplace_back(*layer, source); + } + frameHistory.record(parameters.timePoint, parameters.state.getZoom(), parameters.mapMode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Milliseconds(0)); @@ -329,33 +610,134 @@ void Renderer::Impl::doRender(PaintParameters& parameters) { } 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() { - observer->onInvalidate(); -} - -void Renderer::Impl::onResourceError(std::exception_ptr ptr) { - observer->onResourceError(ptr); -} - void Renderer::Impl::onLowMemory() { BackendScope guard { backend }; backend.getContext().performCleanup(); - renderStyle->onLowMemory(); + for (const auto& entry : renderSources) { + entry.second->onLowMemory(); + } observer->onInvalidate(); } void Renderer::Impl::dumDebugLogs() { - renderStyle->dumpDebugLogs(); + for (const auto& entry : renderSources) { + entry.second->dumpDebugLogs(); + } + + imageManager->dumpDebugLogs(); +} + +RenderLayer* Renderer::Impl::getRenderLayer(const std::string& id) { + auto it = renderLayers.find(id); + return it != renderLayers.end() ? it->second.get() : nullptr; +} + +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..c326ebcac2 100644 --- a/src/mbgl/renderer/renderer_impl.hpp +++ b/src/mbgl/renderer/renderer_impl.hpp @@ -3,9 +3,16 @@ #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.hpp> +#include <mbgl/renderer/render_source_observer.hpp> +#include <mbgl/renderer/render_layer.hpp> +#include <mbgl/renderer/render_light.hpp> #include <mbgl/renderer/frame_history.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 <mbgl/style/image.hpp> #include <memory> #include <string> @@ -15,10 +22,25 @@ namespace mbgl { class UpdateParameters; class PaintParameters; -class RenderStyle; class RenderStaticData; - -class Renderer::Impl : public RenderStyleObserver { +class RenderData; +class RenderedQueryOptions; +class SourceQueryOptions; + +class FileSource; +class GlyphManager; +class ImageManager; +class LineAtlas; +class Scheduler; + +namespace style { +class Image; +class Source; +class Layer; +} // namespace style + +class Renderer::Impl : public GlyphManagerObserver, + public RenderSourceObserver{ public: Impl(RendererBackend&, float pixelRatio_, FileSource&, Scheduler&, GLContextMode, const optional<std::string> programCacheDir); @@ -34,16 +56,30 @@ 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 +94,21 @@ 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; }; } // namespace mbgl |