summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/core-files.cmake3
-rw-r--r--src/mbgl/renderer/paint_parameters.cpp13
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp7
-rw-r--r--src/mbgl/renderer/render_style.cpp453
-rw-r--r--src/mbgl/renderer/render_style.hpp92
-rw-r--r--src/mbgl/renderer/render_style_observer.hpp14
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp438
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp65
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