Files
MapLibreParticleLab/src/mbgl/renderer/render_orchestrator.hpp

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