[core] Introduce RenderOrchestrator
This commit is contained in:
@@ -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",
|
||||
|
||||
630
src/mbgl/renderer/render_orchestrator.cpp
Normal file
630
src/mbgl/renderer/render_orchestrator.cpp
Normal file
@@ -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
|
||||
118
src/mbgl/renderer/render_orchestrator.hpp
Normal file
118
src/mbgl/renderer/render_orchestrator.hpp
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user