summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-06-14 09:52:36 +0300
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-06-14 14:45:45 +0300
commitc443ee672cc5fb12b78f8edfa94147b306a0c5c2 (patch)
treec7d9b94ec83edb173e84cec011d7753f9677a024
parent6dbc1a0ca8e9b1ed1d71489f3ad8f6aaed05405c (diff)
downloadqtlocation-mapboxgl-upstream/mikhail_introduce_orchestrator.tar.gz
[core] Introduce RenderOrchestratorupstream/mikhail_introduce_orchestrator
-rw-r--r--src/core-files.json2
-rw-r--r--src/mbgl/renderer/render_orchestrator.cpp630
-rw-r--r--src/mbgl/renderer/render_orchestrator.hpp118
-rw-r--r--src/mbgl/renderer/renderer.cpp21
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp613
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp104
6 files changed, 783 insertions, 705 deletions
diff --git a/src/core-files.json b/src/core-files.json
index c3ad1291f0..665c203a78 100644
--- a/src/core-files.json
+++ b/src/core-files.json
@@ -127,6 +127,7 @@
"src/mbgl/renderer/pattern_atlas.cpp",
"src/mbgl/renderer/render_layer.cpp",
"src/mbgl/renderer/render_light.cpp",
+ "src/mbgl/renderer/render_orchestrator.cpp",
"src/mbgl/renderer/render_source.cpp",
"src/mbgl/renderer/render_static_data.cpp",
"src/mbgl/renderer/render_tile.cpp",
@@ -643,6 +644,7 @@
"mbgl/renderer/property_evaluator.hpp": "src/mbgl/renderer/property_evaluator.hpp",
"mbgl/renderer/render_layer.hpp": "src/mbgl/renderer/render_layer.hpp",
"mbgl/renderer/render_light.hpp": "src/mbgl/renderer/render_light.hpp",
+ "mbgl/renderer/render_orchestrator.hpp": "src/mbgl/renderer/render_orchestrator.hpp",
"mbgl/renderer/render_pass.hpp": "src/mbgl/renderer/render_pass.hpp",
"mbgl/renderer/render_source.hpp": "src/mbgl/renderer/render_source.hpp",
"mbgl/renderer/render_source_observer.hpp": "src/mbgl/renderer/render_source_observer.hpp",
diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp
new file mode 100644
index 0000000000..76b7752ca1
--- /dev/null
+++ b/src/mbgl/renderer/render_orchestrator.cpp
@@ -0,0 +1,630 @@
+#include <mbgl/renderer/render_orchestrator.hpp>
+
+#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/layermanager/layer_manager.hpp>
+#include <mbgl/renderer/renderer_observer.hpp>
+#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/renderer/render_tree.hpp>
+#include <mbgl/renderer/update_parameters.hpp>
+#include <mbgl/renderer/upload_parameters.hpp>
+#include <mbgl/renderer/pattern_atlas.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/transition_parameters.hpp>
+#include <mbgl/renderer/property_evaluation_parameters.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/style_diff.hpp>
+#include <mbgl/renderer/query.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/geometry/line_atlas.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/text/glyph_manager.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/logging.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+static RendererObserver& nullObserver() {
+ static RendererObserver observer;
+ return observer;
+}
+
+namespace {
+
+class LayerRenderItem final : public RenderItem {
+public:
+ LayerRenderItem(RenderLayer& layer_, RenderSource* source_, uint32_t index_)
+ : layer(layer_), source(source_), index(index_) {}
+ bool operator<(const LayerRenderItem& other) const { return index < other.index; }
+ std::reference_wrapper<RenderLayer> layer;
+ RenderSource* source;
+
+private:
+ bool hasRenderPass(RenderPass pass) const override { return layer.get().hasRenderPass(pass); }
+ void upload(gfx::UploadPass& pass) const override { layer.get().upload(pass); }
+ void render(PaintParameters& parameters) const override { layer.get().render(parameters); }
+ const std::string& getName() const override { return layer.get().getID(); }
+
+ uint32_t index;
+};
+
+class SourceRenderItem final : public RenderItem {
+public:
+ explicit SourceRenderItem(RenderSource& source_)
+ : source(source_) {}
+
+private:
+ bool hasRenderPass(RenderPass) const override { return false; }
+ void upload(gfx::UploadPass& pass) const override { source.get().upload(pass); }
+ void render(PaintParameters& parameters) const override { source.get().finishRender(parameters); }
+ const std::string& getName() const override { return source.get().baseImpl->id; }
+
+ std::reference_wrapper<RenderSource> source;
+};
+
+class RenderTreeImpl final : public RenderTree {
+public:
+ RenderTreeImpl(std::unique_ptr<RenderTreeParameters> parameters_,
+ std::set<LayerRenderItem> layerRenderItems_,
+ std::vector<SourceRenderItem> sourceRenderItems_,
+ LineAtlas& lineAtlas_,
+ PatternAtlas& patternAtlas_)
+ : RenderTree(std::move(parameters_)),
+ layerRenderItems(std::move(layerRenderItems_)),
+ sourceRenderItems(std::move(sourceRenderItems_)),
+ lineAtlas(lineAtlas_),
+ patternAtlas(patternAtlas_) {
+ }
+
+ RenderItems getLayerRenderItems() const override {
+ return { layerRenderItems.begin(), layerRenderItems.end() };
+ }
+ RenderItems getSourceRenderItems() const override {
+ return { sourceRenderItems.begin(), sourceRenderItems.end() };
+ }
+ LineAtlas& getLineAtlas() const override { return lineAtlas; }
+ PatternAtlas& getPatternAtlas() const override { return patternAtlas; }
+
+ std::set<LayerRenderItem> layerRenderItems;
+ std::vector<SourceRenderItem> sourceRenderItems;
+ std::reference_wrapper<LineAtlas> lineAtlas;
+ std::reference_wrapper<PatternAtlas> patternAtlas;
+};
+
+} // namespace
+
+RenderOrchestrator::RenderOrchestrator(
+ bool backgroundLayerAsColor_,
+ optional<std::string> localFontFamily_)
+ : observer(&nullObserver())
+ , glyphManager(std::make_unique<GlyphManager>(std::make_unique<LocalGlyphRasterizer>(std::move(localFontFamily_))))
+ , imageManager(std::make_unique<ImageManager>())
+ , lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 }))
+ , patternAtlas(std::make_unique<PatternAtlas>())
+ , 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>())
+ , placement(std::make_unique<Placement>(TransformState{}, MapMode::Static, TransitionOptions{}, true))
+ , backgroundLayerAsColor(backgroundLayerAsColor_) {
+ glyphManager->setObserver(this);
+ imageManager->setObserver(this);
+}
+
+RenderOrchestrator::~RenderOrchestrator() {
+ if (contextLost) {
+ // Signal all RenderLayers that the context was lost
+ // before cleaning up. At the moment, only CustomLayer is
+ // interested whether rendering context is lost. However, it would be
+ // beneficial for dynamically loaded or other custom built-in plugins.
+ for (const auto& entry : renderLayers) {
+ RenderLayer& layer = *entry.second;
+ layer.markContextDestroyed();
+ }
+ }
+};
+
+void RenderOrchestrator::setObserver(RendererObserver* observer_) {
+ observer = observer_ ? observer_ : &nullObserver();
+}
+
+std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdateParameters& updateParameters) {
+ const bool isMapModeContinuous = updateParameters.mode == MapMode::Continuous;
+ if (!isMapModeContinuous) {
+ // Reset zoom history state.
+ zoomHistory.first = true;
+ }
+
+ if (LayerManager::annotationsEnabled) {
+ updateParameters.annotationManager.updateData();
+ }
+
+ const bool zoomChanged = zoomHistory.update(updateParameters.transformState.getZoom(), updateParameters.timePoint);
+
+ const TransitionOptions transitionOptions = isMapModeContinuous ? updateParameters.transitionOptions : TransitionOptions();
+
+ const TransitionParameters transitionParameters {
+ updateParameters.timePoint,
+ transitionOptions
+ };
+
+ const PropertyEvaluationParameters evaluationParameters {
+ zoomHistory,
+ updateParameters.timePoint,
+ transitionOptions.duration.value_or(isMapModeContinuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero())
+ };
+
+ const TileParameters tileParameters {
+ updateParameters.pixelRatio,
+ updateParameters.debugOptions,
+ updateParameters.transformState,
+ 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;
+
+ // Only trigger tile reparse for changed images. Changed images only need a relayout when they have a different size.
+ bool hasImageDiff = !imageDiff.removed.empty();
+
+ // Remove removed images from sprite atlas.
+ for (const auto& entry : imageDiff.removed) {
+ imageManager->removeImage(entry.first);
+ patternAtlas->removePattern(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) {
+ if (imageManager->updateImage(entry.second.after)) {
+ patternAtlas->removePattern(entry.first);
+ hasImageDiff = true;
+ }
+ }
+
+ imageManager->notifyIfMissingImageAdded();
+ 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) {
+ auto renderLayer = LayerManager::get()->createRenderLayer(entry.second);
+ renderLayer->transition(transitionParameters);
+ renderLayers.emplace(entry.first, std::move(renderLayer));
+ }
+
+ // Update render layers for changed layers.
+ for (const auto& entry : layerDiff.changed) {
+ renderLayers.at(entry.first)->transition(transitionParameters, entry.second.after);
+ }
+
+ if (!layerDiff.removed.empty() || !layerDiff.added.empty() || !layerDiff.changed.empty()) {
+ glyphManager->evict(fontStacks(*updateParameters.layers));
+ }
+
+ // Update layers for class and zoom changes.
+ for (const auto& entry : renderLayers) {
+ RenderLayer& layer = *entry.second;
+ const bool layerAddedOrChanged = layerDiff.added.count(entry.first) || layerDiff.changed.count(entry.first);
+ if (layerAddedOrChanged || zoomChanged || layer.hasTransition() || layer.hasCrossfade()) {
+ 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));
+ }
+ transformState = updateParameters.transformState;
+
+ // Create parameters for the render tree.
+ auto renderTreeParameters = std::make_unique<RenderTreeParameters>(
+ updateParameters.transformState,
+ updateParameters.mode,
+ updateParameters.debugOptions,
+ updateParameters.timePoint,
+ renderLight.getEvaluated());
+
+ std::set<LayerRenderItem> layerRenderItems;
+ std::vector<std::reference_wrapper<RenderLayer>> layersNeedPlacement;
+ auto renderItemsEmplaceHint = layerRenderItems.begin();
+
+ // Update all sources and initialize renderItems.
+ for (const auto& sourceImpl : *sourceImpls) {
+ RenderSource* source = renderSources.at(sourceImpl->id).get();
+ std::vector<Immutable<LayerProperties>> filteredLayersForSource;
+ filteredLayersForSource.reserve(layerImpls->size());
+ bool sourceNeedsRendering = false;
+ bool sourceNeedsRelayout = false;
+
+ uint32_t index = 0u;
+ const auto begin = layerImpls->begin();
+ const auto end = layerImpls->end();
+ for (auto it = begin; it != end; ++it, ++index) {
+ const Immutable<Layer::Impl>& layerImpl = *it;
+ RenderLayer* layer = getRenderLayer(layerImpl->id);
+ const auto* layerInfo = layerImpl->getTypeInfo();
+ const bool layerNeedsRendering = layer->needsRendering();
+ const bool zoomFitsLayer = layer->supportsZoom(zoomHistory.lastZoom);
+ renderTreeParameters->has3D |= (layerInfo->pass3d == LayerTypeInfo::Pass3D::Required);
+
+ if (layerInfo->source != LayerTypeInfo::Source::NotRequired) {
+ if (layerImpl->source == sourceImpl->id) {
+ sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || hasLayoutDifference(layerDiff, layerImpl->id));
+ if (layerNeedsRendering) {
+ filteredLayersForSource.push_back(layer->evaluatedProperties);
+ if (zoomFitsLayer) {
+ sourceNeedsRendering = true;
+ renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, source, index);
+ }
+ }
+ }
+ continue;
+ }
+
+ // Handle layers without source.
+ if (layerNeedsRendering && zoomFitsLayer && sourceImpl.get() == sourceImpls->at(0).get()) {
+ if (backgroundLayerAsColor && layerImpl.get() == layerImpls->at(0).get()) {
+ const auto& solidBackground = layer->getSolidBackground();
+ if (solidBackground) {
+ renderTreeParameters->backgroundColor = *solidBackground;
+ continue; // This layer is shown with background color, and it shall not be added to render items.
+ }
+ }
+ renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, nullptr, index);
+ }
+ }
+ source->update(sourceImpl,
+ filteredLayersForSource,
+ sourceNeedsRendering,
+ sourceNeedsRelayout,
+ tileParameters);
+ }
+
+ renderTreeParameters->loaded = updateParameters.styleLoaded && isLoaded();
+ if (!isMapModeContinuous && !renderTreeParameters->loaded) {
+ return nullptr;
+ }
+
+ std::vector<SourceRenderItem> sourceRenderItems;
+ // Update all matrices and generate data that we should upload to the GPU.
+ for (const auto& entry : renderSources) {
+ if (entry.second->isEnabled()) {
+ entry.second->prepare({renderTreeParameters->transformParams, updateParameters.debugOptions});
+ sourceRenderItems.emplace_back(*entry.second);
+ }
+ }
+
+ for (auto& renderItem : layerRenderItems) {
+ RenderLayer& renderLayer = renderItem.layer;
+ renderLayer.prepare({renderItem.source, *imageManager, *patternAtlas, *lineAtlas, updateParameters.transformState});
+ if (renderLayer.needsPlacement()) {
+ layersNeedPlacement.emplace_back(renderLayer);
+ }
+ }
+
+ {
+ if (!isMapModeContinuous) {
+ // TODO: Think about right way for symbol index to handle still rendering
+ crossTileSymbolIndex.reset();
+ }
+
+ bool symbolBucketsChanged = false;
+ const bool placementChanged = !placement->stillRecent(updateParameters.timePoint);
+ std::set<std::string> usedSymbolLayers;
+ if (placementChanged) {
+ placement = std::make_unique<Placement>(
+ updateParameters.transformState, updateParameters.mode,
+ updateParameters.transitionOptions, updateParameters.crossSourceCollisions,
+ std::move(placement));
+ }
+
+ for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
+ const RenderLayer& layer = *it;
+ if (crossTileSymbolIndex.addLayer(layer, updateParameters.transformState.getLatLng().longitude())) symbolBucketsChanged = true;
+
+ if (placementChanged) {
+ usedSymbolLayers.insert(layer.getID());
+ placement->placeLayer(layer, renderTreeParameters->transformParams.projMatrix, updateParameters.debugOptions & MapDebugOptions::Collision);
+ }
+ }
+
+ if (placementChanged) {
+ placement->commit(updateParameters.timePoint);
+ crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers);
+ for (const auto& entry : renderSources) {
+ entry.second->updateFadingTiles();
+ }
+ } else {
+ placement->setStale();
+ }
+
+ for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
+ placement->updateLayerBuckets(*it, updateParameters.transformState, placementChanged || symbolBucketsChanged);
+ }
+
+ renderTreeParameters->symbolFadeChange = placement->symbolFadeChange(updateParameters.timePoint);
+ }
+
+ renderTreeParameters->needsRepaint = isMapModeContinuous && hasTransitions(updateParameters.timePoint);
+ if (!renderTreeParameters->needsRepaint && renderTreeParameters->loaded) {
+ // Notify observer about unused images when map is fully loaded
+ // and there are no ongoing transitions.
+ imageManager->reduceMemoryUseIfCacheSizeExceedsLimit();
+ }
+
+ return std::make_unique<RenderTreeImpl>(
+ std::move(renderTreeParameters),
+ std::move(layerRenderItems),
+ std::move(sourceRenderItems),
+ *lineAtlas,
+ *patternAtlas);
+}
+
+std::vector<Feature> RenderOrchestrator::queryRenderedFeatures(const ScreenLineString& geometry, 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());
+ }
+ }
+
+ return queryRenderedFeatures(geometry, options, layers);
+}
+
+void RenderOrchestrator::queryRenderedSymbols(std::unordered_map<std::string, std::vector<Feature>>& resultsByLayer,
+ const ScreenLineString& geometry,
+ const std::vector<const RenderLayer*>& layers,
+ const RenderedQueryOptions& options) const {
+
+ auto renderedSymbols = placement->getCollisionIndex().queryRenderedSymbols(geometry);
+ std::vector<std::reference_wrapper<const RetainedQueryData>> bucketQueryData;
+ for (auto entry : renderedSymbols) {
+ bucketQueryData.emplace_back(placement->getQueryData(entry.first));
+ }
+ // Although symbol query is global, symbol results are only sortable within a bucket
+ // For a predictable global sort renderItems, we sort the buckets based on their corresponding tile position
+ std::sort(bucketQueryData.begin(), bucketQueryData.end(), [](const RetainedQueryData& a, const RetainedQueryData& b) {
+ return
+ std::tie(a.tileID.canonical.z, a.tileID.canonical.y, a.tileID.wrap, a.tileID.canonical.x) <
+ std::tie(b.tileID.canonical.z, b.tileID.canonical.y, b.tileID.wrap, b.tileID.canonical.x);
+ });
+
+ for (auto wrappedQueryData : bucketQueryData) {
+ auto& queryData = wrappedQueryData.get();
+ auto bucketSymbols = queryData.featureIndex->lookupSymbolFeatures(renderedSymbols[queryData.bucketInstanceId],
+ options,
+ layers,
+ queryData.tileID,
+ queryData.featureSortOrder);
+
+ for (auto layer : bucketSymbols) {
+ auto& resultFeatures = resultsByLayer[layer.first];
+ std::move(layer.second.begin(), layer.second.end(), std::inserter(resultFeatures, resultFeatures.end()));
+ }
+ }
+}
+
+std::vector<Feature> RenderOrchestrator::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::vector<const RenderLayer*>& layers) const {
+ std::unordered_set<std::string> sourceIDs;
+ for (const RenderLayer* layer : layers) {
+ sourceIDs.emplace(layer->baseImpl->source);
+ }
+
+ mat4 projMatrix;
+ transformState.getProjMatrix(projMatrix);
+
+ 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, projMatrix);
+ std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
+ }
+ }
+
+ queryRenderedSymbols(resultsByLayer, geometry, layers, options);
+
+ std::vector<Feature> result;
+
+ if (resultsByLayer.empty()) {
+ return result;
+ }
+
+ // Combine all results based on the style layer renderItems.
+ for (const auto& layerImpl : *layerImpls) {
+ const RenderLayer* layer = getRenderLayer(layerImpl->id);
+ if (!layer->needsRendering() || !layer->supportsZoom(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> RenderOrchestrator::queryShapeAnnotations(const ScreenLineString& geometry) const {
+ assert(LayerManager::annotationsEnabled);
+ std::vector<const RenderLayer*> shapeAnnotationLayers;
+ RenderedQueryOptions options;
+ for (const auto& layerImpl : *layerImpls) {
+ if (std::mismatch(layerImpl->id.begin(), layerImpl->id.end(),
+ AnnotationManager::ShapeLayerID.begin(), AnnotationManager::ShapeLayerID.end()).second == AnnotationManager::ShapeLayerID.end()) {
+ if (const RenderLayer* layer = getRenderLayer(layerImpl->id)) {
+ shapeAnnotationLayers.emplace_back(layer);
+ }
+ }
+ }
+
+ return queryRenderedFeatures(geometry, options, shapeAnnotationLayers);
+}
+
+std::vector<Feature> RenderOrchestrator::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
+ const RenderSource* source = getRenderSource(sourceID);
+ if (!source) return {};
+
+ return source->querySourceFeatures(options);
+}
+
+FeatureExtensionValue RenderOrchestrator::queryFeatureExtensions(const std::string& sourceID,
+ const Feature& feature,
+ const std::string& extension,
+ const std::string& extensionField,
+ const optional<std::map<std::string, Value>>& args) const {
+ if (RenderSource* renderSource = getRenderSource(sourceID)) {
+ return renderSource->queryFeatureExtensions(feature, extension, extensionField, args);
+ }
+ return {};
+}
+
+void RenderOrchestrator::reduceMemoryUse() {
+ for (const auto& entry : renderSources) {
+ entry.second->reduceMemoryUse();
+ }
+ imageManager->reduceMemoryUse();
+ observer->onInvalidate();
+}
+
+void RenderOrchestrator::dumpDebugLogs() {
+ for (const auto& entry : renderSources) {
+ entry.second->dumpDebugLogs();
+ }
+
+ imageManager->dumpDebugLogs();
+}
+
+RenderLayer* RenderOrchestrator::getRenderLayer(const std::string& id) {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
+}
+
+const RenderLayer* RenderOrchestrator::getRenderLayer(const std::string& id) const {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
+}
+
+RenderSource* RenderOrchestrator::getRenderSource(const std::string& id) const {
+ auto it = renderSources.find(id);
+ return it != renderSources.end() ? it->second.get() : nullptr;
+}
+
+bool RenderOrchestrator::hasTransitions(TimePoint timePoint) const {
+ if (renderLight.hasTransition()) {
+ return true;
+ }
+
+ for (const auto& entry : renderLayers) {
+ if (entry.second->hasTransition()) {
+ return true;
+ }
+ }
+
+ if (placement->hasTransitions(timePoint)) {
+ return true;
+ }
+
+ for (const auto& entry : renderSources) {
+ if (entry.second->hasFadingTiles()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool RenderOrchestrator::isLoaded() const {
+ for (const auto& entry: renderSources) {
+ if (!entry.second->isLoaded()) {
+ return false;
+ }
+ }
+
+ if (!imageManager->isLoaded()) {
+ return false;
+ }
+
+ return true;
+}
+
+void RenderOrchestrator::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 RenderOrchestrator::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 RenderOrchestrator::onTileChanged(RenderSource&, const OverscaledTileID&) {
+ observer->onInvalidate();
+}
+
+void RenderOrchestrator::onStyleImageMissing(const std::string& id, std::function<void()> done) {
+ observer->onStyleImageMissing(id, std::move(done));
+}
+
+void RenderOrchestrator::onRemoveUnusedStyleImages(const std::vector<std::string>& unusedImageIDs) {
+ observer->onRemoveUnusedStyleImages(unusedImageIDs);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp
new file mode 100644
index 0000000000..a60bac2e16
--- /dev/null
+++ b/src/mbgl/renderer/render_orchestrator.hpp
@@ -0,0 +1,118 @@
+#pragma once
+
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/renderer/render_source_observer.hpp>
+#include <mbgl/renderer/render_light.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/map/zoom_history.hpp>
+#include <mbgl/text/cross_tile_symbol_index.hpp>
+#include <mbgl/text/glyph_manager_observer.hpp>
+#include <mbgl/renderer/image_manager_observer.hpp>
+#include <mbgl/text/placement.hpp>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace mbgl {
+
+class RendererObserver;
+class RenderSource;
+class RenderLayer;
+class UpdateParameters;
+class RenderStaticData;
+class RenderedQueryOptions;
+class SourceQueryOptions;
+class GlyphManager;
+class ImageManager;
+class LineAtlas;
+class PatternAtlas;
+class CrossTileSymbolIndex;
+class RenderTree;
+
+class RenderOrchestrator final : public GlyphManagerObserver,
+ public ImageManagerObserver,
+ public RenderSourceObserver {
+public:
+ RenderOrchestrator(
+ bool backgroundLayerAsColor_,
+ optional<std::string> localFontFamily_);
+ ~RenderOrchestrator() override;
+
+ void markContextLost() {
+ contextLost = true;
+ };
+ // TODO: Introduce RenderOrchestratorObserver.
+ void setObserver(RendererObserver*);
+
+ std::unique_ptr<RenderTree> createRenderTree(const UpdateParameters&);
+
+ std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const;
+ std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
+ std::vector<Feature> queryShapeAnnotations(const ScreenLineString&) const;
+
+ FeatureExtensionValue queryFeatureExtensions(const std::string& sourceID,
+ const Feature& feature,
+ const std::string& extension,
+ const std::string& extensionField,
+ const optional<std::map<std::string, Value>>& args) const;
+
+ void reduceMemoryUse();
+ void dumpDebugLogs();
+
+private:
+ bool isLoaded() const;
+ bool hasTransitions(TimePoint) const;
+
+ RenderSource* getRenderSource(const std::string& id) const;
+
+ RenderLayer* getRenderLayer(const std::string& id);
+ const RenderLayer* getRenderLayer(const std::string& id) const;
+
+ void queryRenderedSymbols(std::unordered_map<std::string, std::vector<Feature>>& resultsByLayer,
+ const ScreenLineString& geometry,
+ const std::vector<const RenderLayer*>& layers,
+ const RenderedQueryOptions& options) const;
+
+ std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&, const std::vector<const RenderLayer*>&) 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;
+
+ // ImageManagerObserver implementation
+ void onStyleImageMissing(const std::string&, std::function<void()>) override;
+ void onRemoveUnusedStyleImages(const std::vector<std::string>&) override;
+
+ RendererObserver* observer;
+
+ ZoomHistory zoomHistory;
+ TransformState transformState;
+
+ std::unique_ptr<GlyphManager> glyphManager;
+ std::unique_ptr<ImageManager> imageManager;
+ std::unique_ptr<LineAtlas> lineAtlas;
+ std::unique_ptr<PatternAtlas> patternAtlas;
+
+ 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;
+
+ CrossTileSymbolIndex crossTileSymbolIndex;
+ std::unique_ptr<Placement> placement;
+
+ const bool backgroundLayerAsColor;
+ bool contextLost = false;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
index 3fa0082c40..76e618a50f 100644
--- a/src/mbgl/renderer/renderer.cpp
+++ b/src/mbgl/renderer/renderer.cpp
@@ -24,29 +24,30 @@ Renderer::~Renderer() {
}
void Renderer::markContextLost() {
- impl->markContextLost();
+ impl->orchestrator.markContextLost();
}
void Renderer::setObserver(RendererObserver* observer) {
impl->setObserver(observer);
+ impl->orchestrator.setObserver(observer);
}
void Renderer::render(const UpdateParameters& updateParameters) {
- if (auto renderTree = impl->createRenderTree(updateParameters)) {
+ if (auto renderTree = impl->orchestrator.createRenderTree(updateParameters)) {
impl->render(*renderTree);
}
}
std::vector<Feature> Renderer::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const {
- return impl->queryRenderedFeatures(geometry, options);
+ return impl->orchestrator.queryRenderedFeatures(geometry, options);
}
std::vector<Feature> Renderer::queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options) const {
- return impl->queryRenderedFeatures({ point }, options);
+ return impl->orchestrator.queryRenderedFeatures({ point }, options);
}
std::vector<Feature> Renderer::queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options) const {
- return impl->queryRenderedFeatures(
+ return impl->orchestrator.queryRenderedFeatures(
{
box.min,
{box.max.x, box.min.y},
@@ -72,7 +73,7 @@ AnnotationIDs Renderer::queryShapeAnnotations(const ScreenBox& box) const {
if (!LayerManager::annotationsEnabled) {
return {};
}
- auto features = impl->queryShapeAnnotations({
+ auto features = impl->orchestrator.queryShapeAnnotations({
box.min,
{box.max.x, box.min.y},
box.max,
@@ -99,7 +100,7 @@ AnnotationIDs Renderer::getAnnotationIDs(const std::vector<Feature>& features) c
}
std::vector<Feature> Renderer::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
- return impl->querySourceFeatures(sourceID, options);
+ return impl->orchestrator.querySourceFeatures(sourceID, options);
}
FeatureExtensionValue Renderer::queryFeatureExtensions(const std::string& sourceID,
@@ -107,16 +108,16 @@ FeatureExtensionValue Renderer::queryFeatureExtensions(const std::string& source
const std::string& extension,
const std::string& extensionField,
const optional<std::map<std::string, Value>>& args) const {
- return impl->queryFeatureExtensions(sourceID, feature, extension, extensionField, args);
+ return impl->orchestrator.queryFeatureExtensions(sourceID, feature, extension, extensionField, args);
}
void Renderer::dumpDebugLogs() {
- impl->dumpDebugLogs();
+ impl->orchestrator.dumpDebugLogs();
}
void Renderer::reduceMemoryUse() {
- gfx::BackendScope guard { impl->backend };
impl->reduceMemoryUse();
+ impl->orchestrator.reduceMemoryUse();
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index ef8afadb35..c536497c30 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -1,35 +1,17 @@
-#include <mbgl/annotation/annotation_manager.hpp>
-#include <mbgl/layermanager/layer_manager.hpp>
#include <mbgl/renderer/renderer_impl.hpp>
-#include <mbgl/renderer/renderer_observer.hpp>
-#include <mbgl/renderer/render_source.hpp>
-#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/renderer/render_static_data.hpp>
-#include <mbgl/renderer/render_tree.hpp>
-#include <mbgl/renderer/update_parameters.hpp>
-#include <mbgl/renderer/upload_parameters.hpp>
-#include <mbgl/renderer/pattern_atlas.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/transition_parameters.hpp>
-#include <mbgl/renderer/property_evaluation_parameters.hpp>
-#include <mbgl/renderer/tile_parameters.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/style_diff.hpp>
-#include <mbgl/renderer/query.hpp>
+
+#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/gfx/backend_scope.hpp>
-#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/gfx/renderer_backend.hpp>
#include <mbgl/gfx/upload_pass.hpp>
#include <mbgl/gfx/render_pass.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/renderable.hpp>
-#include <mbgl/geometry/line_atlas.hpp>
-#include <mbgl/style/source_impl.hpp>
-#include <mbgl/style/transition_options.hpp>
-#include <mbgl/text/glyph_manager.hpp>
-#include <mbgl/tile/tile.hpp>
-#include <mbgl/util/math.hpp>
+#include <mbgl/renderer/pattern_atlas.hpp>
+#include <mbgl/renderer/renderer_observer.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/renderer/render_tree.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/logging.hpp>
@@ -42,382 +24,26 @@ static RendererObserver& nullObserver() {
return observer;
}
-class LayerRenderItem final : public RenderItem {
-public:
- LayerRenderItem(RenderLayer& layer_, RenderSource* source_, uint32_t index_)
- : layer(layer_), source(source_), index(index_) {}
- bool operator<(const LayerRenderItem& other) const { return index < other.index; }
- std::reference_wrapper<RenderLayer> layer;
- RenderSource* source;
-
-private:
- bool hasRenderPass(RenderPass pass) const override { return layer.get().hasRenderPass(pass); }
- void upload(gfx::UploadPass& pass) const override { layer.get().upload(pass); }
- void render(PaintParameters& parameters) const override { layer.get().render(parameters); }
- const std::string& getName() const override { return layer.get().getID(); }
-
- uint32_t index;
-};
-
-class SourceRenderItem final : public RenderItem {
-public:
- explicit SourceRenderItem(RenderSource& source_)
- : source(source_) {}
-
-private:
- bool hasRenderPass(RenderPass) const override { return false; }
- void upload(gfx::UploadPass& pass) const override { source.get().upload(pass); }
- void render(PaintParameters& parameters) const override { source.get().finishRender(parameters); }
- const std::string& getName() const override { return source.get().baseImpl->id; }
-
- std::reference_wrapper<RenderSource> source;
-};
-
-class RenderTreeImpl final : public RenderTree {
-public:
- RenderTreeImpl(std::unique_ptr<RenderTreeParameters> parameters_,
- std::set<LayerRenderItem> layerRenderItems_,
- std::vector<SourceRenderItem> sourceRenderItems_,
- LineAtlas& lineAtlas_,
- PatternAtlas& patternAtlas_)
- : RenderTree(std::move(parameters_)),
- layerRenderItems(std::move(layerRenderItems_)),
- sourceRenderItems(std::move(sourceRenderItems_)),
- lineAtlas(lineAtlas_),
- patternAtlas(patternAtlas_) {
- }
-
- RenderItems getLayerRenderItems() const override {
- return { layerRenderItems.begin(), layerRenderItems.end() };
- }
- RenderItems getSourceRenderItems() const override {
- return { sourceRenderItems.begin(), sourceRenderItems.end() };
- }
- LineAtlas& getLineAtlas() const override { return lineAtlas; }
- PatternAtlas& getPatternAtlas() const override { return patternAtlas; }
-
- std::set<LayerRenderItem> layerRenderItems;
- std::vector<SourceRenderItem> sourceRenderItems;
- std::reference_wrapper<LineAtlas> lineAtlas;
- std::reference_wrapper<PatternAtlas> patternAtlas;
-};
-
-
Renderer::Impl::Impl(gfx::RendererBackend& backend_,
float pixelRatio_,
- const optional<std::string> programCacheDir_,
- const optional<std::string> localFontFamily_)
- : backend(backend_)
+ optional<std::string> programCacheDir_,
+ optional<std::string> localFontFamily_)
+ : orchestrator(!backend_.contextIsShared(), std::move(localFontFamily_))
+ , backend(backend_)
, observer(&nullObserver())
, pixelRatio(pixelRatio_)
- , programCacheDir(std::move(programCacheDir_))
- , localFontFamily(std::move(localFontFamily_))
- , glyphManager(std::make_unique<GlyphManager>(std::make_unique<LocalGlyphRasterizer>(localFontFamily)))
- , imageManager(std::make_unique<ImageManager>())
- , lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 }))
- , patternAtlas(std::make_unique<PatternAtlas>())
- , 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>())
- , placement(std::make_unique<Placement>(TransformState{}, MapMode::Static, TransitionOptions{}, true)) {
- glyphManager->setObserver(this);
- imageManager->setObserver(this);
+ , programCacheDir(std::move(programCacheDir_)) {
+
}
Renderer::Impl::~Impl() {
assert(gfx::BackendScope::exists());
-
- if (contextLost) {
- // Signal all RenderLayers that the context was lost
- // before cleaning up. At the moment, only CustomLayer is
- // interested whether rendering context is lost. However, it would be
- // beneficial for dynamically loaded or other custom built-in plugins.
- for (const auto& entry : renderLayers) {
- RenderLayer& layer = *entry.second;
- layer.markContextDestroyed();
- }
- }
};
void Renderer::Impl::setObserver(RendererObserver* observer_) {
observer = observer_ ? observer_ : &nullObserver();
}
-std::unique_ptr<RenderTree> Renderer::Impl::createRenderTree(const UpdateParameters& updateParameters) {
- const bool isMapModeContinuous = updateParameters.mode == MapMode::Continuous;
- if (!isMapModeContinuous) {
- // Reset zoom history state.
- zoomHistory.first = true;
- }
-
- if (LayerManager::annotationsEnabled) {
- updateParameters.annotationManager.updateData();
- }
-
- const bool zoomChanged = zoomHistory.update(updateParameters.transformState.getZoom(), updateParameters.timePoint);
-
- const TransitionOptions transitionOptions = isMapModeContinuous ? updateParameters.transitionOptions : TransitionOptions();
-
- const TransitionParameters transitionParameters {
- updateParameters.timePoint,
- transitionOptions
- };
-
- const PropertyEvaluationParameters evaluationParameters {
- zoomHistory,
- updateParameters.timePoint,
- transitionOptions.duration.value_or(isMapModeContinuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero())
- };
-
- const TileParameters tileParameters {
- updateParameters.pixelRatio,
- updateParameters.debugOptions,
- updateParameters.transformState,
- 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;
-
- // Only trigger tile reparse for changed images. Changed images only need a relayout when they have a different size.
- bool hasImageDiff = !imageDiff.removed.empty();
-
- // Remove removed images from sprite atlas.
- for (const auto& entry : imageDiff.removed) {
- imageManager->removeImage(entry.first);
- patternAtlas->removePattern(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) {
- if (imageManager->updateImage(entry.second.after)) {
- patternAtlas->removePattern(entry.first);
- hasImageDiff = true;
- }
- }
-
- imageManager->notifyIfMissingImageAdded();
- 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) {
- auto renderLayer = LayerManager::get()->createRenderLayer(entry.second);
- renderLayer->transition(transitionParameters);
- renderLayers.emplace(entry.first, std::move(renderLayer));
- }
-
- // Update render layers for changed layers.
- for (const auto& entry : layerDiff.changed) {
- renderLayers.at(entry.first)->transition(transitionParameters, entry.second.after);
- }
-
- if (!layerDiff.removed.empty() || !layerDiff.added.empty() || !layerDiff.changed.empty()) {
- glyphManager->evict(fontStacks(*updateParameters.layers));
- }
-
- // Update layers for class and zoom changes.
- for (const auto& entry : renderLayers) {
- RenderLayer& layer = *entry.second;
- const bool layerAddedOrChanged = layerDiff.added.count(entry.first) || layerDiff.changed.count(entry.first);
- if (layerAddedOrChanged || zoomChanged || layer.hasTransition() || layer.hasCrossfade()) {
- 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));
- }
- transformState = updateParameters.transformState;
-
- // Create parameters for the render tree.
- auto renderTreeParameters = std::make_unique<RenderTreeParameters>(
- updateParameters.transformState,
- updateParameters.mode,
- updateParameters.debugOptions,
- updateParameters.timePoint,
- renderLight.getEvaluated());
-
- std::set<LayerRenderItem> layerRenderItems;
- std::vector<std::reference_wrapper<RenderLayer>> layersNeedPlacement;
- auto renderItemsEmplaceHint = layerRenderItems.begin();
-
- // Update all sources and initialize renderItems.
- for (const auto& sourceImpl : *sourceImpls) {
- RenderSource* source = renderSources.at(sourceImpl->id).get();
- std::vector<Immutable<LayerProperties>> filteredLayersForSource;
- filteredLayersForSource.reserve(layerImpls->size());
- bool sourceNeedsRendering = false;
- bool sourceNeedsRelayout = false;
-
- uint32_t index = 0u;
- const auto begin = layerImpls->begin();
- const auto end = layerImpls->end();
- for (auto it = begin; it != end; ++it, ++index) {
- const Immutable<Layer::Impl>& layerImpl = *it;
- RenderLayer* layer = getRenderLayer(layerImpl->id);
- const auto* layerInfo = layerImpl->getTypeInfo();
- const bool layerNeedsRendering = layer->needsRendering();
- const bool zoomFitsLayer = layer->supportsZoom(zoomHistory.lastZoom);
- renderTreeParameters->has3D = (renderTreeParameters->has3D || layerInfo->pass3d == LayerTypeInfo::Pass3D::Required);
-
- if (layerInfo->source != LayerTypeInfo::Source::NotRequired) {
- if (layerImpl->source == sourceImpl->id) {
- sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || hasLayoutDifference(layerDiff, layerImpl->id));
- if (layerNeedsRendering) {
- filteredLayersForSource.push_back(layer->evaluatedProperties);
- if (zoomFitsLayer) {
- sourceNeedsRendering = true;
- renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, source, index);
- }
- }
- }
- continue;
- }
-
- // Handle layers without source.
- if (layerNeedsRendering && zoomFitsLayer && sourceImpl.get() == sourceImpls->at(0).get()) {
- if (!backend.contextIsShared() && layerImpl.get() == layerImpls->at(0).get()) {
- const auto& solidBackground = layer->getSolidBackground();
- if (solidBackground) {
- renderTreeParameters->backgroundColor = *solidBackground;
- continue; // This layer is shown with background color, and it shall not be added to render items.
- }
- }
- renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, nullptr, index);
- }
- }
- source->update(sourceImpl,
- filteredLayersForSource,
- sourceNeedsRendering,
- sourceNeedsRelayout,
- tileParameters);
- }
-
- renderTreeParameters->loaded = updateParameters.styleLoaded && isLoaded();
- if (!isMapModeContinuous && !renderTreeParameters->loaded) {
- return nullptr;
- }
-
- std::vector<SourceRenderItem> sourceRenderItems;
- // Update all matrices and generate data that we should upload to the GPU.
- for (const auto& entry : renderSources) {
- if (entry.second->isEnabled()) {
- entry.second->prepare({renderTreeParameters->transformParams, updateParameters.debugOptions});
- sourceRenderItems.emplace_back(*entry.second);
- }
- }
-
- for (auto& renderItem : layerRenderItems) {
- RenderLayer& renderLayer = renderItem.layer;
- renderLayer.prepare({renderItem.source, *imageManager, *patternAtlas, *lineAtlas, updateParameters.transformState});
- if (renderLayer.needsPlacement()) {
- layersNeedPlacement.emplace_back(renderLayer);
- }
- }
-
- {
- if (!isMapModeContinuous) {
- // TODO: Think about right way for symbol index to handle still rendering
- crossTileSymbolIndex.reset();
- }
-
- bool symbolBucketsChanged = false;
- const bool placementChanged = !placement->stillRecent(updateParameters.timePoint);
- std::set<std::string> usedSymbolLayers;
- if (placementChanged) {
- placement = std::make_unique<Placement>(
- updateParameters.transformState, updateParameters.mode,
- updateParameters.transitionOptions, updateParameters.crossSourceCollisions,
- std::move(placement));
- }
-
- for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
- const RenderLayer& layer = *it;
- if (crossTileSymbolIndex.addLayer(layer, updateParameters.transformState.getLatLng().longitude())) symbolBucketsChanged = true;
-
- if (placementChanged) {
- usedSymbolLayers.insert(layer.getID());
- placement->placeLayer(layer, renderTreeParameters->transformParams.projMatrix, updateParameters.debugOptions & MapDebugOptions::Collision);
- }
- }
-
- if (placementChanged) {
- placement->commit(updateParameters.timePoint);
- crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers);
- for (const auto& entry : renderSources) {
- entry.second->updateFadingTiles();
- }
- } else {
- placement->setStale();
- }
-
- for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
- placement->updateLayerBuckets(*it, updateParameters.transformState, placementChanged || symbolBucketsChanged);
- }
-
- renderTreeParameters->symbolFadeChange = placement->symbolFadeChange(updateParameters.timePoint);
- }
-
- renderTreeParameters->needsRepaint = isMapModeContinuous && hasTransitions(updateParameters.timePoint);
- if (!renderTreeParameters->needsRepaint && renderTreeParameters->loaded) {
- // Notify observer about unused images when map is fully loaded
- // and there are no ongoing transitions.
- imageManager->reduceMemoryUseIfCacheSizeExceedsLimit();
- }
-
- return std::make_unique<RenderTreeImpl>(
- std::move(renderTreeParameters),
- std::move(layerRenderItems),
- std::move(sourceRenderItems),
- *lineAtlas,
- *patternAtlas);
-}
-
void Renderer::Impl::render(const RenderTree& renderTree) {
if (renderState == RenderState::Never) {
observer->onWillStartRenderingMap();
@@ -596,224 +222,9 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
}
}
-std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, 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());
- }
- }
-
- return queryRenderedFeatures(geometry, options, layers);
-}
-
-void Renderer::Impl::queryRenderedSymbols(std::unordered_map<std::string, std::vector<Feature>>& resultsByLayer,
- const ScreenLineString& geometry,
- const std::vector<const RenderLayer*>& layers,
- const RenderedQueryOptions& options) const {
-
- auto renderedSymbols = placement->getCollisionIndex().queryRenderedSymbols(geometry);
- std::vector<std::reference_wrapper<const RetainedQueryData>> bucketQueryData;
- for (auto entry : renderedSymbols) {
- bucketQueryData.emplace_back(placement->getQueryData(entry.first));
- }
- // Although symbol query is global, symbol results are only sortable within a bucket
- // For a predictable global sort renderItems, we sort the buckets based on their corresponding tile position
- std::sort(bucketQueryData.begin(), bucketQueryData.end(), [](const RetainedQueryData& a, const RetainedQueryData& b) {
- return
- std::tie(a.tileID.canonical.z, a.tileID.canonical.y, a.tileID.wrap, a.tileID.canonical.x) <
- std::tie(b.tileID.canonical.z, b.tileID.canonical.y, b.tileID.wrap, b.tileID.canonical.x);
- });
-
- for (auto wrappedQueryData : bucketQueryData) {
- auto& queryData = wrappedQueryData.get();
- auto bucketSymbols = queryData.featureIndex->lookupSymbolFeatures(renderedSymbols[queryData.bucketInstanceId],
- options,
- layers,
- queryData.tileID,
- queryData.featureSortOrder);
-
- for (auto layer : bucketSymbols) {
- auto& resultFeatures = resultsByLayer[layer.first];
- std::move(layer.second.begin(), layer.second.end(), std::inserter(resultFeatures, resultFeatures.end()));
- }
- }
-}
-
-std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::vector<const RenderLayer*>& layers) const {
- std::unordered_set<std::string> sourceIDs;
- for (const RenderLayer* layer : layers) {
- sourceIDs.emplace(layer->baseImpl->source);
- }
-
- mat4 projMatrix;
- transformState.getProjMatrix(projMatrix);
-
- 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, projMatrix);
- std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
- }
- }
-
- queryRenderedSymbols(resultsByLayer, geometry, layers, options);
-
- std::vector<Feature> result;
-
- if (resultsByLayer.empty()) {
- return result;
- }
-
- // Combine all results based on the style layer renderItems.
- for (const auto& layerImpl : *layerImpls) {
- const RenderLayer* layer = getRenderLayer(layerImpl->id);
- if (!layer->needsRendering() || !layer->supportsZoom(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::queryShapeAnnotations(const ScreenLineString& geometry) const {
- assert(LayerManager::annotationsEnabled);
- std::vector<const RenderLayer*> shapeAnnotationLayers;
- RenderedQueryOptions options;
- for (const auto& layerImpl : *layerImpls) {
- if (std::mismatch(layerImpl->id.begin(), layerImpl->id.end(),
- AnnotationManager::ShapeLayerID.begin(), AnnotationManager::ShapeLayerID.end()).second == AnnotationManager::ShapeLayerID.end()) {
- if (const RenderLayer* layer = getRenderLayer(layerImpl->id)) {
- shapeAnnotationLayers.emplace_back(layer);
- }
- }
- }
-
- return queryRenderedFeatures(geometry, options, shapeAnnotationLayers);
-}
-
-std::vector<Feature> Renderer::Impl::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
- const RenderSource* source = getRenderSource(sourceID);
- if (!source) return {};
-
- return source->querySourceFeatures(options);
-}
-
-FeatureExtensionValue Renderer::Impl::queryFeatureExtensions(const std::string& sourceID,
- const Feature& feature,
- const std::string& extension,
- const std::string& extensionField,
- const optional<std::map<std::string, Value>>& args) const {
- if (RenderSource* renderSource = getRenderSource(sourceID)) {
- return renderSource->queryFeatureExtensions(feature, extension, extensionField, args);
- }
- return {};
-}
-
void Renderer::Impl::reduceMemoryUse() {
assert(gfx::BackendScope::exists());
- for (const auto& entry : renderSources) {
- entry.second->reduceMemoryUse();
- }
backend.getContext().reduceMemoryUsage();
- imageManager->reduceMemoryUse();
- observer->onInvalidate();
-}
-
-void Renderer::Impl::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(TimePoint timePoint) const {
- if (renderLight.hasTransition()) {
- return true;
- }
-
- for (const auto& entry : renderLayers) {
- if (entry.second->hasTransition()) {
- return true;
- }
- }
-
- if (placement->hasTransitions(timePoint)) {
- return true;
- }
-
- for (const auto& entry : renderSources) {
- if (entry.second->hasFadingTiles()) {
- 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();
-}
-
-void Renderer::Impl::onStyleImageMissing(const std::string& id, std::function<void()> done) {
- observer->onStyleImageMissing(id, std::move(done));
-}
-
-void Renderer::Impl::onRemoveUnusedStyleImages(const std::vector<std::string>& unusedImageIDs) {
- observer->onRemoveUnusedStyleImages(unusedImageIDs);
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 693c4b6513..85e37a014a 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -1,102 +1,39 @@
#pragma once
-#include <mbgl/renderer/renderer.hpp>
-#include <mbgl/renderer/render_source_observer.hpp>
-#include <mbgl/renderer/render_light.hpp>
-#include <mbgl/style/image.hpp>
-#include <mbgl/style/source.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/map/transform_state.hpp>
-#include <mbgl/map/zoom_history.hpp>
-#include <mbgl/text/cross_tile_symbol_index.hpp>
-#include <mbgl/text/glyph_manager_observer.hpp>
-#include <mbgl/renderer/image_manager_observer.hpp>
-#include <mbgl/text/placement.hpp>
+#include <mbgl/renderer/render_orchestrator.hpp>
#include <memory>
#include <string>
-#include <vector>
namespace mbgl {
class RendererObserver;
-class RenderSource;
-class RenderLayer;
-class UpdateParameters;
class RenderStaticData;
-class RenderedQueryOptions;
-class SourceQueryOptions;
-class GlyphManager;
-class ImageManager;
-class LineAtlas;
-class PatternAtlas;
-class CrossTileSymbolIndex;
class RenderTree;
namespace gfx {
class RendererBackend;
} // namespace gfx
-class Renderer::Impl : public GlyphManagerObserver,
- public ImageManagerObserver,
- public RenderSourceObserver{
+class Renderer::Impl {
public:
Impl(gfx::RendererBackend&,
float pixelRatio_,
- const optional<std::string> programCacheDir,
- const optional<std::string> localFontFamily_);
- ~Impl() final;
+ optional<std::string> programCacheDir,
+ optional<std::string> localFontFamily_);
+ ~Impl();
- void markContextLost() {
- contextLost = true;
- };
+private:
+ friend class Renderer;
void setObserver(RendererObserver*);
- std::unique_ptr<RenderTree> createRenderTree(const UpdateParameters&);
void render(const RenderTree&);
- std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const;
- std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
- std::vector<Feature> queryShapeAnnotations(const ScreenLineString&) const;
-
- FeatureExtensionValue queryFeatureExtensions(const std::string& sourceID,
- const Feature& feature,
- const std::string& extension,
- const std::string& extensionField,
- const optional<std::map<std::string, Value>>& args) const;
-
void reduceMemoryUse();
- void dumpDebugLogs();
-
-private:
- bool isLoaded() const;
- bool hasTransitions(TimePoint) const;
-
- RenderSource* getRenderSource(const std::string& id) const;
-
- RenderLayer* getRenderLayer(const std::string& id);
- const RenderLayer* getRenderLayer(const std::string& id) const;
-
- void queryRenderedSymbols(std::unordered_map<std::string, std::vector<Feature>>& resultsByLayer,
- const ScreenLineString& geometry,
- const std::vector<const RenderLayer*>& layers,
- const RenderedQueryOptions& options) const;
-
- std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&, const std::vector<const RenderLayer*>&) 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;
-
- // ImageManagerObserver implementation
- void onStyleImageMissing(const std::string&, std::function<void()>) override;
- void onRemoveUnusedStyleImages(const std::vector<std::string>&) final;
-
- friend class Renderer;
+ // TODO: Move orchestrator to Map::Impl.
+ RenderOrchestrator orchestrator;
gfx::RendererBackend& backend;
@@ -104,7 +41,7 @@ private:
const float pixelRatio;
const optional<std::string> programCacheDir;
- const optional<std::string> localFontFamily;
+ std::unique_ptr<RenderStaticData> staticData;
enum class RenderState {
Never,
@@ -113,27 +50,6 @@ private:
};
RenderState renderState = RenderState::Never;
- ZoomHistory zoomHistory;
- TransformState transformState;
-
- std::unique_ptr<GlyphManager> glyphManager;
- std::unique_ptr<ImageManager> imageManager;
- std::unique_ptr<LineAtlas> lineAtlas;
- std::unique_ptr<PatternAtlas> patternAtlas;
- 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;
-
- CrossTileSymbolIndex crossTileSymbolIndex;
- std::unique_ptr<Placement> placement;
-
- bool contextLost = false;
};
} // namespace mbgl