From c443ee672cc5fb12b78f8edfa94147b306a0c5c2 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 14 Jun 2019 09:52:36 +0300 Subject: [core] Introduce RenderOrchestrator --- src/core-files.json | 2 + src/mbgl/renderer/render_orchestrator.cpp | 630 ++++++++++++++++++++++++++++++ src/mbgl/renderer/render_orchestrator.hpp | 118 ++++++ src/mbgl/renderer/renderer.cpp | 21 +- src/mbgl/renderer/renderer_impl.cpp | 613 +---------------------------- src/mbgl/renderer/renderer_impl.hpp | 104 +---- 6 files changed, 783 insertions(+), 705 deletions(-) create mode 100644 src/mbgl/renderer/render_orchestrator.cpp create mode 100644 src/mbgl/renderer/render_orchestrator.hpp 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 source; +}; + +class RenderTreeImpl final : public RenderTree { +public: + RenderTreeImpl(std::unique_ptr parameters_, + std::set layerRenderItems_, + std::vector 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 layerRenderItems; + std::vector sourceRenderItems; + std::reference_wrapper lineAtlas; + std::reference_wrapper patternAtlas; +}; + +} // namespace + +RenderOrchestrator::RenderOrchestrator( + bool backgroundLayerAsColor_, + optional localFontFamily_) + : observer(&nullObserver()) + , glyphManager(std::make_unique(std::make_unique(std::move(localFontFamily_)))) + , imageManager(std::make_unique()) + , lineAtlas(std::make_unique(Size{ 256, 512 })) + , patternAtlas(std::make_unique()) + , imageImpls(makeMutable>>()) + , sourceImpls(makeMutable>>()) + , layerImpls(makeMutable>>()) + , renderLight(makeMutable()) + , placement(std::make_unique(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 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::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( + updateParameters.transformState, + updateParameters.mode, + updateParameters.debugOptions, + updateParameters.timePoint, + renderLight.getEvaluated()); + + std::set layerRenderItems; + std::vector> 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> 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& 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 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 usedSymbolLayers; + if (placementChanged) { + placement = std::make_unique( + 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( + std::move(renderTreeParameters), + std::move(layerRenderItems), + std::move(sourceRenderItems), + *lineAtlas, + *patternAtlas); +} + +std::vector RenderOrchestrator::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const { + std::vector 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>& resultsByLayer, + const ScreenLineString& geometry, + const std::vector& layers, + const RenderedQueryOptions& options) const { + + auto renderedSymbols = placement->getCollisionIndex().queryRenderedSymbols(geometry); + std::vector> 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 RenderOrchestrator::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::vector& layers) const { + std::unordered_set sourceIDs; + for (const RenderLayer* layer : layers) { + sourceIDs.emplace(layer->baseImpl->source); + } + + mat4 projMatrix; + transformState.getProjMatrix(projMatrix); + + std::unordered_map> 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 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 RenderOrchestrator::queryShapeAnnotations(const ScreenLineString& geometry) const { + assert(LayerManager::annotationsEnabled); + std::vector 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 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>& 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 done) { + observer->onStyleImageMissing(id, std::move(done)); +} + +void RenderOrchestrator::onRemoveUnusedStyleImages(const std::vector& 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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 localFontFamily_); + ~RenderOrchestrator() override; + + void markContextLost() { + contextLost = true; + }; + // TODO: Introduce RenderOrchestratorObserver. + void setObserver(RendererObserver*); + + std::unique_ptr createRenderTree(const UpdateParameters&); + + std::vector queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const; + std::vector querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; + std::vector queryShapeAnnotations(const ScreenLineString&) const; + + FeatureExtensionValue queryFeatureExtensions(const std::string& sourceID, + const Feature& feature, + const std::string& extension, + const std::string& extensionField, + const optional>& 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>& resultsByLayer, + const ScreenLineString& geometry, + const std::vector& layers, + const RenderedQueryOptions& options) const; + + std::vector queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&, const std::vector&) 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) override; + void onRemoveUnusedStyleImages(const std::vector&) override; + + RendererObserver* observer; + + ZoomHistory zoomHistory; + TransformState transformState; + + std::unique_ptr glyphManager; + std::unique_ptr imageManager; + std::unique_ptr lineAtlas; + std::unique_ptr patternAtlas; + + Immutable>> imageImpls; + Immutable>> sourceImpls; + Immutable>> layerImpls; + + std::unordered_map> renderSources; + std::unordered_map> renderLayers; + RenderLight renderLight; + + CrossTileSymbolIndex crossTileSymbolIndex; + std::unique_ptr 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 Renderer::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const { - return impl->queryRenderedFeatures(geometry, options); + return impl->orchestrator.queryRenderedFeatures(geometry, options); } std::vector Renderer::queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options) const { - return impl->queryRenderedFeatures({ point }, options); + return impl->orchestrator.queryRenderedFeatures({ point }, options); } std::vector 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& features) c } std::vector 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>& 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 -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include #include -#include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -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 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 source; -}; - -class RenderTreeImpl final : public RenderTree { -public: - RenderTreeImpl(std::unique_ptr parameters_, - std::set layerRenderItems_, - std::vector 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 layerRenderItems; - std::vector sourceRenderItems; - std::reference_wrapper lineAtlas; - std::reference_wrapper patternAtlas; -}; - - Renderer::Impl::Impl(gfx::RendererBackend& backend_, float pixelRatio_, - const optional programCacheDir_, - const optional localFontFamily_) - : backend(backend_) + optional programCacheDir_, + optional 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(std::make_unique(localFontFamily))) - , imageManager(std::make_unique()) - , lineAtlas(std::make_unique(Size{ 256, 512 })) - , patternAtlas(std::make_unique()) - , imageImpls(makeMutable>>()) - , sourceImpls(makeMutable>>()) - , layerImpls(makeMutable>>()) - , renderLight(makeMutable()) - , placement(std::make_unique(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 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::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( - updateParameters.transformState, - updateParameters.mode, - updateParameters.debugOptions, - updateParameters.timePoint, - renderLight.getEvaluated()); - - std::set layerRenderItems; - std::vector> 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> 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& 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 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 usedSymbolLayers; - if (placementChanged) { - placement = std::make_unique( - 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( - 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 Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const { - std::vector 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>& resultsByLayer, - const ScreenLineString& geometry, - const std::vector& layers, - const RenderedQueryOptions& options) const { - - auto renderedSymbols = placement->getCollisionIndex().queryRenderedSymbols(geometry); - std::vector> 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 Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::vector& layers) const { - std::unordered_set sourceIDs; - for (const RenderLayer* layer : layers) { - sourceIDs.emplace(layer->baseImpl->source); - } - - mat4 projMatrix; - transformState.getProjMatrix(projMatrix); - - std::unordered_map> 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 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 Renderer::Impl::queryShapeAnnotations(const ScreenLineString& geometry) const { - assert(LayerManager::annotationsEnabled); - std::vector 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 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>& 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 done) { - observer->onStyleImageMissing(id, std::move(done)); -} - -void Renderer::Impl::onRemoveUnusedStyleImages(const std::vector& 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include -#include 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 programCacheDir, - const optional localFontFamily_); - ~Impl() final; + optional programCacheDir, + optional localFontFamily_); + ~Impl(); - void markContextLost() { - contextLost = true; - }; +private: + friend class Renderer; void setObserver(RendererObserver*); - std::unique_ptr createRenderTree(const UpdateParameters&); void render(const RenderTree&); - std::vector queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const; - std::vector querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; - std::vector queryShapeAnnotations(const ScreenLineString&) const; - - FeatureExtensionValue queryFeatureExtensions(const std::string& sourceID, - const Feature& feature, - const std::string& extension, - const std::string& extensionField, - const optional>& 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>& resultsByLayer, - const ScreenLineString& geometry, - const std::vector& layers, - const RenderedQueryOptions& options) const; - - std::vector queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&, const std::vector&) 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) override; - void onRemoveUnusedStyleImages(const std::vector&) 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 programCacheDir; - const optional localFontFamily; + std::unique_ptr staticData; enum class RenderState { Never, @@ -113,27 +50,6 @@ private: }; RenderState renderState = RenderState::Never; - ZoomHistory zoomHistory; - TransformState transformState; - - std::unique_ptr glyphManager; - std::unique_ptr imageManager; - std::unique_ptr lineAtlas; - std::unique_ptr patternAtlas; - std::unique_ptr staticData; - - Immutable>> imageImpls; - Immutable>> sourceImpls; - Immutable>> layerImpls; - - std::unordered_map> renderSources; - std::unordered_map> renderLayers; - RenderLight renderLight; - - CrossTileSymbolIndex crossTileSymbolIndex; - std::unique_ptr placement; - - bool contextLost = false; }; } // namespace mbgl -- cgit v1.2.1