433 lines
18 KiB
C++
433 lines
18 KiB
C++
#pragma once
|
|
|
|
#include <mbgl/renderer/layer_group.hpp>
|
|
#include <mbgl/actor/scheduler.hpp>
|
|
#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_tree.hpp>
|
|
#include <mbgl/renderer/retained_underlay_cache.hpp>
|
|
|
|
#include <atomic>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace mbgl {
|
|
class ChangeRequest;
|
|
class RendererObserver;
|
|
class RenderSource;
|
|
class UpdateParameters;
|
|
class RenderStaticData;
|
|
class RenderedQueryOptions;
|
|
class SourceQueryOptions;
|
|
class GlyphManager;
|
|
class ImageManager;
|
|
class LineAtlas;
|
|
class PatternAtlas;
|
|
class CrossTileSymbolIndex;
|
|
class RenderTree;
|
|
|
|
namespace gfx {
|
|
class ShaderRegistry;
|
|
class Drawable;
|
|
using DrawablePtr = std::shared_ptr<Drawable>;
|
|
class DynamicTextureAtlas;
|
|
using DynamicTextureAtlasPtr = std::shared_ptr<gfx::DynamicTextureAtlas>;
|
|
} // namespace gfx
|
|
|
|
namespace style {
|
|
class LayerProperties;
|
|
} // namespace style
|
|
|
|
using ImmutableLayer = Immutable<style::Layer::Impl>;
|
|
|
|
struct ParticleFastPathDynamicState {
|
|
bool particleNeedsRepaint = false;
|
|
bool nonParticleNeedsRepaint = false;
|
|
bool blockingTransition = false;
|
|
bool placementTransition = false;
|
|
bool fadingTiles = false;
|
|
bool pendingChanges = false;
|
|
};
|
|
|
|
class RenderOrchestrator final : public GlyphManagerObserver, public ImageManagerObserver, public RenderSourceObserver {
|
|
public:
|
|
RenderOrchestrator(bool backgroundLayerAsColor_,
|
|
TaggedScheduler& threadPool_,
|
|
const std::optional<std::string>& localFontFamily_);
|
|
~RenderOrchestrator() override;
|
|
|
|
#if MLN_RENDER_BACKEND_OPENGL
|
|
void enableAndroidEmulatorGoldfishMitigation(bool enable) { androidGoldfishMitigationEnabled = enable; }
|
|
#endif
|
|
|
|
void markContextLost();
|
|
// TODO: Introduce RenderOrchestratorObserver.
|
|
void setObserver(RendererObserver*);
|
|
|
|
std::unique_ptr<RenderTree> createRenderTree(const std::shared_ptr<UpdateParameters>&, gfx::DynamicTextureAtlasPtr);
|
|
|
|
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 std::optional<std::map<std::string, Value>>& args) const;
|
|
|
|
void setFeatureState(const std::string& sourceID,
|
|
const std::optional<std::string>& layerID,
|
|
const std::string& featureID,
|
|
const FeatureState& state);
|
|
|
|
void getFeatureState(FeatureState& state,
|
|
const std::string& sourceID,
|
|
const std::optional<std::string>& layerID,
|
|
const std::string& featureID) const;
|
|
|
|
void removeFeatureState(const std::string& sourceID,
|
|
const std::optional<std::string>& sourceLayerID,
|
|
const std::optional<std::string>& featureID,
|
|
const std::optional<std::string>& stateKey);
|
|
|
|
void setTileCacheEnabled(bool);
|
|
bool getTileCacheEnabled() const;
|
|
void reduceMemoryUse();
|
|
void dumpDebugLogs();
|
|
void collectPlacedSymbolData(bool);
|
|
const std::vector<PlacedSymbolData>& getPlacedSymbolsData() const;
|
|
void clearData();
|
|
|
|
void update(const std::shared_ptr<UpdateParameters>&);
|
|
|
|
bool addLayerGroup(LayerGroupBasePtr);
|
|
bool removeLayerGroup(const LayerGroupBasePtr&);
|
|
size_t numLayerGroups() const noexcept;
|
|
std::optional<int32_t> getRetainedDynamicBoundary() const noexcept { return retainedDynamicBoundary; }
|
|
const ContinuousLayerRangeResolution& getContinuousLayerRange() const noexcept { return continuousLayerRange; }
|
|
const ResolvedRenderSegmentPlan& getRenderSegmentPlan() const noexcept { return renderSegmentPlan; }
|
|
int32_t getOrderedLayerCount() const noexcept { return static_cast<int32_t>(orderedLayers.size()); }
|
|
bool retainedUnderlayUsesPlacement(int32_t boundary) const;
|
|
bool retainedUnderlayIsStable(TimePoint, int32_t boundary) const;
|
|
bool retainedUnderlayHasUnsupportedLayer(int32_t boundary) const;
|
|
bool retainedRangeUsesPlacement(int32_t begin, int32_t endExclusive) const;
|
|
bool retainedRangeHasPlacementCapableLayer(int32_t begin, int32_t endExclusive) const;
|
|
bool retainedPlacementTransitionActive(TimePoint timePoint) const;
|
|
bool retainedRangeIsStable(TimePoint, int32_t begin, int32_t endExclusive) const;
|
|
struct RetainedSegmentSourceState {
|
|
uint64_t revision = 0;
|
|
bool ready = false;
|
|
bool stable = false;
|
|
const char* reason = "unknown-dependency";
|
|
};
|
|
RetainedSegmentSourceState retainedSegmentSourceState(int32_t begin, int32_t endExclusive) const;
|
|
bool retainedSegmentIsStable(TimePoint, int32_t begin, int32_t endExclusive) const;
|
|
bool retainedGlobalResourcesReady() const;
|
|
bool retainedGlobalLightTransition() const;
|
|
bool retainedRangeHasUnsupportedLayer(int32_t begin, int32_t endExclusive) const;
|
|
bool continuousRangeSupportsParticleFastPath(int32_t begin, int32_t endExclusive) const;
|
|
uint64_t retainedRangeContentFingerprint(int32_t begin, int32_t endExclusive) const;
|
|
ParticleFastPathDynamicState particleFastPathDynamicState(TimePoint) const;
|
|
uint64_t getRetainedUnderlayContentRevision() const noexcept {
|
|
return retainedUnderlayContentRevision.load(std::memory_order_acquire);
|
|
}
|
|
RetainedUnderlayReason getRetainedUnderlayContentReason() const noexcept {
|
|
return retainedUnderlayContentReason.load(std::memory_order_acquire);
|
|
}
|
|
void updateLayerIndex(LayerGroupBasePtr, int32_t newIndex);
|
|
|
|
template <typename Func /* void(LayerGroupBase&) */>
|
|
void visitLayerGroups(Func f) {
|
|
for (auto& pair : layerGroupsByLayerIndex) {
|
|
if (pair.second) {
|
|
try {
|
|
f(*pair.second);
|
|
} catch (...) {
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
|
void visitLayerGroupsInRange(int32_t begin, int32_t endExclusive, Func f, bool* failed = nullptr) {
|
|
size_t ordinal = static_cast<size_t>(std::distance(layerGroupsByLayerIndex.begin(),
|
|
layerGroupsByLayerIndex.lower_bound(begin)));
|
|
for (auto it = layerGroupsByLayerIndex.lower_bound(begin);
|
|
it != layerGroupsByLayerIndex.end() && it->first < endExclusive; ++it, ++ordinal) {
|
|
if (it->second) {
|
|
try { f(*it->second, ordinal); } catch (...) {
|
|
if (failed) *failed = true;
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
|
void visitLayerGroupsInRangeReversed(int32_t begin, int32_t endExclusive, Func f, bool* failed = nullptr) {
|
|
auto first = layerGroupsByLayerIndex.lower_bound(begin);
|
|
auto last = layerGroupsByLayerIndex.lower_bound(endExclusive);
|
|
size_t ordinal = static_cast<size_t>(std::distance(layerGroupsByLayerIndex.begin(), last));
|
|
while (last != first) {
|
|
--last;
|
|
--ordinal;
|
|
if (last->second) {
|
|
try { f(*last->second, ordinal); } catch (...) {
|
|
if (failed) *failed = true;
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
|
void visitLayerGroupsBefore(int32_t boundary, Func f) {
|
|
size_t ordinal = 0;
|
|
for (auto& pair : layerGroupsByLayerIndex) {
|
|
if (!retainedLayerGroupInRange(pair.first, boundary, RetainedLayerGroupRange::Before)) break;
|
|
if (pair.second) {
|
|
try {
|
|
f(*pair.second, ordinal);
|
|
} catch (...) {
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
++ordinal;
|
|
}
|
|
}
|
|
|
|
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
|
void visitLayerGroupsFrom(int32_t boundary, Func f) {
|
|
size_t ordinal = static_cast<size_t>(std::distance(layerGroupsByLayerIndex.begin(),
|
|
layerGroupsByLayerIndex.lower_bound(boundary)));
|
|
for (auto it = layerGroupsByLayerIndex.lower_bound(boundary); it != layerGroupsByLayerIndex.end(); ++it) {
|
|
if (!retainedLayerGroupInRange(it->first, boundary, RetainedLayerGroupRange::From)) continue;
|
|
if (it->second) {
|
|
try {
|
|
f(*it->second, ordinal);
|
|
} catch (...) {
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
++ordinal;
|
|
}
|
|
}
|
|
|
|
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
|
void visitLayerGroupsBeforeReversed(int32_t boundary, Func f) {
|
|
auto end = layerGroupsByLayerIndex.lower_bound(boundary);
|
|
size_t ordinal = static_cast<size_t>(std::distance(layerGroupsByLayerIndex.begin(), end));
|
|
while (end != layerGroupsByLayerIndex.begin()) {
|
|
--end;
|
|
--ordinal;
|
|
if (end->second) {
|
|
try {
|
|
f(*end->second, ordinal);
|
|
} catch (...) {
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Func /* void(LayerGroupBase&, size_t originalOrdinal) */>
|
|
void visitLayerGroupsFromReversed(int32_t boundary, Func f) {
|
|
auto begin = layerGroupsByLayerIndex.lower_bound(boundary);
|
|
size_t ordinal = layerGroupsByLayerIndex.size();
|
|
for (auto it = layerGroupsByLayerIndex.rbegin(); it.base() != begin; ++it) {
|
|
--ordinal;
|
|
if (it->second) {
|
|
try {
|
|
f(*it->second, ordinal);
|
|
} catch (...) {
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Func /* void(LayerGroupBase&) */>
|
|
void visitLayerGroupsReversed(Func f) {
|
|
for (auto rit = layerGroupsByLayerIndex.rbegin(); rit != layerGroupsByLayerIndex.rend(); ++rit) {
|
|
if (rit->second) {
|
|
try {
|
|
f(*rit->second);
|
|
} catch (...) {
|
|
observer->onRenderError(std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateLayers(gfx::ShaderRegistry&,
|
|
gfx::Context&,
|
|
const TransformState&,
|
|
const std::shared_ptr<UpdateParameters>&,
|
|
const RenderTree&);
|
|
void updateParticleLayers(gfx::ShaderRegistry&,
|
|
gfx::Context&,
|
|
const TransformState&,
|
|
const std::shared_ptr<UpdateParameters>&,
|
|
const RenderTree&);
|
|
|
|
void processChanges();
|
|
|
|
bool addRenderTarget(RenderTargetPtr);
|
|
bool removeRenderTarget(const RenderTargetPtr&);
|
|
|
|
template <typename Func /* void(RenderTarget&) */>
|
|
void visitRenderTargets(Func f) {
|
|
for (auto& renderTarget : renderTargets) {
|
|
f(*renderTarget);
|
|
}
|
|
}
|
|
|
|
void updateDebugLayerGroups(const RenderTree& renderTree, PaintParameters& parameters);
|
|
|
|
template <typename Func /* void(LayerGroupBase&) */>
|
|
void visitDebugLayerGroups(Func f) {
|
|
for (auto& pair : debugLayerGroups) {
|
|
if (pair.second) {
|
|
f(*pair.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
const ZoomHistory& getZoomHistory() const { return zoomHistory; }
|
|
|
|
private:
|
|
// Allows the focused teardown test to install a pending tile-backed source.
|
|
friend struct RenderOrchestratorTeardownTestAccess;
|
|
|
|
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::unordered_map<std::string, const RenderLayer*>& layers,
|
|
const RenderedQueryOptions& options) const;
|
|
|
|
std::vector<Feature> queryRenderedFeatures(const ScreenLineString&,
|
|
const RenderedQueryOptions&,
|
|
const std::unordered_map<std::string, const RenderLayer*>&) const;
|
|
|
|
// GlyphManagerObserver implementation.
|
|
void onGlyphsLoaded(const FontStack&, const GlyphRange&) override;
|
|
void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override;
|
|
void onGlyphsRequested(const FontStack&, const GlyphRange&) override;
|
|
// RenderSourceObserver implementation.
|
|
void onTileChanged(RenderSource&, const OverscaledTileID&) override;
|
|
void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
|
|
void onTileAction(RenderSource&, TileOperation, const OverscaledTileID&, const std::string&) override;
|
|
|
|
// ImageManagerObserver implementation
|
|
void onStyleImageMissing(const std::string&, const std::function<void()>&) override;
|
|
void onRemoveUnusedStyleImages(const std::vector<std::string>&) override;
|
|
|
|
/// Move changes into the pending set, clearing the provided collection
|
|
void addChanges(UniqueChangeRequestVec&);
|
|
void advanceRetainedUnderlayContentRevision(
|
|
RetainedUnderlayReason,
|
|
const std::optional<std::string>& sourceId = std::nullopt) noexcept;
|
|
void advanceRetainedSourceRevision(RetainedUnderlayReason, const std::string& sourceId) noexcept;
|
|
void recordReadinessMutation(const char* eventType,
|
|
RetainedUnderlayReason reason,
|
|
const std::optional<std::string>& sourceId = std::nullopt,
|
|
const std::string& tileAction = {}) noexcept;
|
|
RendererReadinessDiagnostics buildReadinessDiagnostics(bool styleLoaded, bool spriteLoaded) const;
|
|
|
|
RendererObserver* observer;
|
|
|
|
ZoomHistory zoomHistory;
|
|
TransformState transformState;
|
|
|
|
std::shared_ptr<GlyphManager> glyphManager;
|
|
std::shared_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;
|
|
PlacementController placementController;
|
|
|
|
const bool backgroundLayerAsColor;
|
|
bool contextLost = false;
|
|
bool placedSymbolDataCollected = false;
|
|
bool tileCacheEnabled = true;
|
|
bool retainedInputStateInitialized = false;
|
|
bool retainedSpriteLoaded = false;
|
|
std::string retainedGlyphURL;
|
|
const void* retainedFontFacesIdentity = nullptr;
|
|
std::atomic<uint64_t> retainedUnderlayContentRevision{1};
|
|
RenderSegmentRevisionBook retainedSegmentRevisions;
|
|
std::atomic<RetainedUnderlayReason> retainedUnderlayContentReason{RetainedUnderlayReason::None};
|
|
|
|
struct SourceReadinessEventState {
|
|
uint64_t lastSourceMutationSequence = 0;
|
|
uint64_t lastTileChangedSequence = 0;
|
|
uint64_t lastTileActionSequence = 0;
|
|
std::string lastTileAction{"none"};
|
|
std::string lastMutationReason{"none"};
|
|
};
|
|
mutable std::mutex readinessDiagnosticsMutex;
|
|
uint64_t readinessEventSequence = 0;
|
|
std::unordered_map<std::string, SourceReadinessEventState> sourceReadinessEvents;
|
|
RenderMutationDiagnostics lastReadinessMutation;
|
|
|
|
#if MLN_RENDER_BACKEND_OPENGL
|
|
bool androidGoldfishMitigationEnabled{false};
|
|
#endif
|
|
|
|
// Vectors with reserved capacity of layerImpls->size() to avoid
|
|
// reallocation on each frame.
|
|
std::vector<Immutable<style::LayerProperties>> filteredLayersForSource;
|
|
RenderLayerReferences orderedLayers;
|
|
std::vector<StyleLayerDiagnostics> retainedStyleLayers;
|
|
ResolvedRenderSegmentPlan renderSegmentPlan;
|
|
bool renderSegmentStyleReady = false;
|
|
RenderLayerReferences layersNeedPlacement;
|
|
|
|
TaggedScheduler threadPool;
|
|
|
|
std::vector<std::unique_ptr<ChangeRequest>> pendingChanges;
|
|
|
|
using LayerGroupMap = std::multimap<int32_t, LayerGroupBasePtr>;
|
|
LayerGroupMap layerGroupsByLayerIndex;
|
|
std::optional<int32_t> retainedDynamicBoundary;
|
|
ContinuousLayerRangeResolution continuousLayerRange;
|
|
|
|
std::vector<RenderTargetPtr> renderTargets;
|
|
RenderItem::DebugLayerGroupMap debugLayerGroups;
|
|
};
|
|
|
|
} // namespace mbgl
|