[core] Merge RenderStyle into Renderer::Impl
This commit is contained in:
@@ -194,9 +194,6 @@ set(MBGL_CORE_FILES
|
||||
src/mbgl/renderer/render_source_observer.hpp
|
||||
src/mbgl/renderer/render_static_data.cpp
|
||||
src/mbgl/renderer/render_static_data.hpp
|
||||
src/mbgl/renderer/render_style.cpp
|
||||
src/mbgl/renderer/render_style.hpp
|
||||
src/mbgl/renderer/render_style_observer.hpp
|
||||
src/mbgl/renderer/render_tile.cpp
|
||||
src/mbgl/renderer/render_tile.hpp
|
||||
src/mbgl/renderer/renderer.cpp
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <mbgl/renderer/paint_parameters.hpp>
|
||||
#include <mbgl/renderer/update_parameters.hpp>
|
||||
#include <mbgl/renderer/render_style.hpp>
|
||||
#include <mbgl/renderer/render_static_data.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
|
||||
@@ -11,17 +10,19 @@ PaintParameters::PaintParameters(gl::Context& context_,
|
||||
GLContextMode contextMode_,
|
||||
RendererBackend& backend_,
|
||||
const UpdateParameters& updateParameters,
|
||||
RenderStyle& style,
|
||||
const EvaluatedLight& evaluatedLight_,
|
||||
RenderStaticData& staticData_,
|
||||
FrameHistory& frameHistory_)
|
||||
FrameHistory& frameHistory_,
|
||||
ImageManager& imageManager_,
|
||||
LineAtlas& lineAtlas_)
|
||||
: context(context_),
|
||||
backend(backend_),
|
||||
state(updateParameters.transformState),
|
||||
evaluatedLight(style.getRenderLight().getEvaluated()),
|
||||
evaluatedLight(evaluatedLight_),
|
||||
staticData(staticData_),
|
||||
frameHistory(frameHistory_),
|
||||
imageManager(*style.imageManager),
|
||||
lineAtlas(*style.lineAtlas),
|
||||
imageManager(imageManager_),
|
||||
lineAtlas(lineAtlas_),
|
||||
mapMode(updateParameters.mode),
|
||||
debugOptions(updateParameters.debugOptions),
|
||||
contextMode(contextMode_),
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace mbgl {
|
||||
|
||||
class RendererBackend;
|
||||
class UpdateParameters;
|
||||
class RenderStyle;
|
||||
class RenderStaticData;
|
||||
class FrameHistory;
|
||||
class Programs;
|
||||
@@ -31,9 +30,11 @@ public:
|
||||
GLContextMode,
|
||||
RendererBackend&,
|
||||
const UpdateParameters&,
|
||||
RenderStyle&,
|
||||
const EvaluatedLight&,
|
||||
RenderStaticData&,
|
||||
FrameHistory&);
|
||||
FrameHistory&,
|
||||
ImageManager&,
|
||||
LineAtlas&);
|
||||
|
||||
gl::Context& context;
|
||||
RendererBackend& backend;
|
||||
|
||||
@@ -1,453 +0,0 @@
|
||||
#include <mbgl/renderer/render_style.hpp>
|
||||
#include <mbgl/renderer/render_style_observer.hpp>
|
||||
#include <mbgl/renderer/update_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_source.hpp>
|
||||
#include <mbgl/renderer/render_item.hpp>
|
||||
#include <mbgl/renderer/render_tile.hpp>
|
||||
#include <mbgl/renderer/layers/render_background_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_circle_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_custom_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_fill_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_line_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_raster_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
|
||||
#include <mbgl/renderer/backend_scope.hpp>
|
||||
#include <mbgl/renderer/style_diff.hpp>
|
||||
#include <mbgl/renderer/image_manager.hpp>
|
||||
#include <mbgl/renderer/query.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/source_impl.hpp>
|
||||
#include <mbgl/style/transition_options.hpp>
|
||||
#include <mbgl/sprite/sprite_loader.hpp>
|
||||
#include <mbgl/text/glyph_manager.hpp>
|
||||
#include <mbgl/geometry/line_atlas.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;
|
||||
|
||||
RenderStyleObserver nullObserver;
|
||||
|
||||
RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_)
|
||||
: scheduler(scheduler_),
|
||||
fileSource(fileSource_),
|
||||
glyphManager(std::make_unique<GlyphManager>(fileSource)),
|
||||
imageManager(std::make_unique<ImageManager>()),
|
||||
lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })),
|
||||
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>()),
|
||||
observer(&nullObserver) {
|
||||
glyphManager->setObserver(this);
|
||||
}
|
||||
|
||||
RenderStyle::~RenderStyle() {
|
||||
assert(BackendScope::exists()); // Required for custom layers.
|
||||
}
|
||||
|
||||
void RenderStyle::setObserver(RenderStyleObserver* observer_) {
|
||||
observer = observer_;
|
||||
}
|
||||
|
||||
std::vector<const RenderLayer*> RenderStyle::getRenderLayers() const {
|
||||
std::vector<const RenderLayer*> result;
|
||||
result.reserve(renderLayers.size());
|
||||
for (const auto& layer : *layerImpls) {
|
||||
result.push_back(getRenderLayer(layer->id));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RenderLayer* RenderStyle::getRenderLayer(const std::string& id) {
|
||||
auto it = renderLayers.find(id);
|
||||
return it != renderLayers.end() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
const RenderLayer* RenderStyle::getRenderLayer(const std::string& id) const {
|
||||
auto it = renderLayers.find(id);
|
||||
return it != renderLayers.end() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
const RenderLight& RenderStyle::getRenderLight() const {
|
||||
return renderLight;
|
||||
}
|
||||
|
||||
void RenderStyle::update(const UpdateParameters& parameters) {
|
||||
assert(BackendScope::exists()); // Required for custom layers.
|
||||
|
||||
const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint);
|
||||
|
||||
const TransitionParameters transitionParameters {
|
||||
parameters.timePoint,
|
||||
parameters.mode == MapMode::Continuous ? parameters.transitionOptions : TransitionOptions()
|
||||
};
|
||||
|
||||
const PropertyEvaluationParameters evaluationParameters {
|
||||
zoomHistory,
|
||||
parameters.timePoint,
|
||||
parameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero()
|
||||
};
|
||||
|
||||
const TileParameters tileParameters {
|
||||
parameters.pixelRatio,
|
||||
parameters.debugOptions,
|
||||
parameters.transformState,
|
||||
parameters.scheduler,
|
||||
parameters.fileSource,
|
||||
parameters.mode,
|
||||
parameters.annotationManager,
|
||||
*imageManager,
|
||||
*glyphManager,
|
||||
parameters.prefetchZoomDelta
|
||||
};
|
||||
|
||||
glyphManager->setURL(parameters.glyphURL);
|
||||
|
||||
// Update light.
|
||||
const bool lightChanged = renderLight.impl != parameters.light;
|
||||
|
||||
if (lightChanged) {
|
||||
renderLight.impl = parameters.light;
|
||||
renderLight.transition(transitionParameters);
|
||||
}
|
||||
|
||||
if (lightChanged || zoomChanged || renderLight.hasTransition()) {
|
||||
renderLight.evaluate(evaluationParameters);
|
||||
}
|
||||
|
||||
|
||||
const ImageDifference imageDiff = diffImages(imageImpls, parameters.images);
|
||||
imageImpls = parameters.images;
|
||||
|
||||
// Remove removed images from sprite atlas.
|
||||
for (const auto& entry : imageDiff.removed) {
|
||||
imageManager->removeImage(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) {
|
||||
imageManager->updateImage(entry.second.after);
|
||||
}
|
||||
|
||||
imageManager->setLoaded(parameters.spriteLoaded);
|
||||
|
||||
|
||||
const LayerDifference layerDiff = diffLayers(layerImpls, parameters.layers);
|
||||
layerImpls = parameters.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) {
|
||||
renderLayers.emplace(entry.first, RenderLayer::create(entry.second));
|
||||
}
|
||||
|
||||
// Update render layers for changed layers.
|
||||
for (const auto& entry : layerDiff.changed) {
|
||||
renderLayers.at(entry.first)->setImpl(entry.second.after);
|
||||
}
|
||||
|
||||
// Update layers for class and zoom changes.
|
||||
for (const auto& entry : renderLayers) {
|
||||
RenderLayer& layer = *entry.second;
|
||||
const bool layerAdded = layerDiff.added.count(entry.first);
|
||||
const bool layerChanged = layerDiff.changed.count(entry.first);
|
||||
|
||||
if (layerAdded || layerChanged) {
|
||||
layer.transition(transitionParameters);
|
||||
}
|
||||
|
||||
if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) {
|
||||
layer.evaluate(evaluationParameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const SourceDifference sourceDiff = diffSources(sourceImpls, parameters.sources);
|
||||
sourceImpls = parameters.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));
|
||||
}
|
||||
|
||||
// Update all sources.
|
||||
for (const auto& source : *sourceImpls) {
|
||||
std::vector<Immutable<Layer::Impl>> filteredLayers;
|
||||
bool needsRendering = false;
|
||||
bool needsRelayout = false;
|
||||
|
||||
for (const auto& layer : *layerImpls) {
|
||||
if (layer->type == LayerType::Background ||
|
||||
layer->type == LayerType::Custom ||
|
||||
layer->source != source->id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!needsRendering && getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) {
|
||||
needsRendering = true;
|
||||
}
|
||||
|
||||
if (!needsRelayout && (
|
||||
hasLayoutDifference(layerDiff, layer->id) ||
|
||||
!imageDiff.added.empty() ||
|
||||
!imageDiff.removed.empty() ||
|
||||
!imageDiff.changed.empty())) {
|
||||
needsRelayout = true;
|
||||
}
|
||||
|
||||
filteredLayers.push_back(layer);
|
||||
}
|
||||
|
||||
renderSources.at(source->id)->update(source,
|
||||
filteredLayers,
|
||||
needsRendering,
|
||||
needsRelayout,
|
||||
tileParameters);
|
||||
}
|
||||
}
|
||||
|
||||
RenderSource* RenderStyle::getRenderSource(const std::string& id) const {
|
||||
auto it = renderSources.find(id);
|
||||
return it != renderSources.end() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
bool RenderStyle::hasTransitions() const {
|
||||
if (renderLight.hasTransition()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& entry : renderLayers) {
|
||||
if (entry.second->hasTransition()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RenderStyle::isLoaded() const {
|
||||
for (const auto& entry: renderSources) {
|
||||
if (!entry.second->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!imageManager->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) {
|
||||
RenderData result;
|
||||
|
||||
for (const auto& entry : renderSources) {
|
||||
if (entry.second->isEnabled()) {
|
||||
result.sources.insert(entry.second.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& layerImpl : *layerImpls) {
|
||||
RenderLayer* layer = getRenderLayer(layerImpl->id);
|
||||
assert(layer);
|
||||
|
||||
if (!layer->needsRendering(zoomHistory.lastZoom)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) {
|
||||
if (debugOptions & MapDebugOptions::Overdraw) {
|
||||
// We want to skip glClear optimization in overdraw mode.
|
||||
result.order.emplace_back(*layer, nullptr);
|
||||
continue;
|
||||
}
|
||||
const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated;
|
||||
if (layerImpl.get() == layerImpls->at(0).get() && paint.get<BackgroundPattern>().from.empty()) {
|
||||
// This is a solid background. We can use glClear().
|
||||
result.backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
|
||||
} else {
|
||||
// This is a textured background, or not the bottommost layer. We need to render it with a quad.
|
||||
result.order.emplace_back(*layer, nullptr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (layer->is<RenderCustomLayer>()) {
|
||||
result.order.emplace_back(*layer, nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
RenderSource* source = getRenderSource(layer->baseImpl->source);
|
||||
if (!source) {
|
||||
Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool symbolLayer = layer->is<RenderSymbolLayer>();
|
||||
|
||||
auto sortedTiles = source->getRenderTiles();
|
||||
if (symbolLayer) {
|
||||
// Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn
|
||||
// on top of each other, with lower symbols being drawn on top of higher symbols.
|
||||
std::sort(sortedTiles.begin(), sortedTiles.end(),
|
||||
[angle](const RenderTile& a, const RenderTile& b) {
|
||||
Point<float> pa(a.id.canonical.x, a.id.canonical.y);
|
||||
Point<float> pb(b.id.canonical.x, b.id.canonical.y);
|
||||
|
||||
auto par = util::rotate(pa, angle);
|
||||
auto pbr = util::rotate(pb, angle);
|
||||
|
||||
return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x);
|
||||
});
|
||||
} else {
|
||||
std::sort(sortedTiles.begin(), sortedTiles.end(),
|
||||
[](const auto& a, const auto& b) { return a.get().id < b.get().id; });
|
||||
}
|
||||
|
||||
std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
|
||||
for (auto& sortedTile : sortedTiles) {
|
||||
auto& tile = sortedTile.get();
|
||||
if (!tile.tile.isRenderable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We're not clipping symbol layers, so when we have both parents and children of symbol
|
||||
// layers, we drop all children in favor of their parent to avoid duplicate labels.
|
||||
// See https://github.com/mapbox/mapbox-gl-native/issues/2482
|
||||
if (symbolLayer) {
|
||||
bool skip = false;
|
||||
// Look back through the buckets we decided to render to find out whether there is
|
||||
// already a bucket from this layer that is a parent of this tile. Tiles are ordered
|
||||
// by zoom level when we obtain them from getTiles().
|
||||
for (auto it = sortedTilesForInsertion.rbegin();
|
||||
it != sortedTilesForInsertion.rend(); ++it) {
|
||||
if (tile.tile.id.isChildOf(it->get().tile.id)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto bucket = tile.tile.getBucket(*layer->baseImpl);
|
||||
if (bucket) {
|
||||
sortedTilesForInsertion.emplace_back(tile);
|
||||
tile.used = true;
|
||||
}
|
||||
}
|
||||
layer->setRenderTiles(std::move(sortedTilesForInsertion));
|
||||
result.order.emplace_back(*layer, source);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Feature> RenderStyle::queryRenderedFeatures(const ScreenLineString& geometry,
|
||||
const TransformState& transformState,
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> sourceIDs;
|
||||
for (const RenderLayer* layer : layers) {
|
||||
sourceIDs.emplace(layer->baseImpl->source);
|
||||
}
|
||||
|
||||
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);
|
||||
std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Feature> result;
|
||||
|
||||
if (resultsByLayer.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Combine all results based on the style layer order.
|
||||
for (const auto& layerImpl : *layerImpls) {
|
||||
const RenderLayer* layer = getRenderLayer(layerImpl->id);
|
||||
if (!layer->needsRendering(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;
|
||||
}
|
||||
|
||||
void RenderStyle::onLowMemory() {
|
||||
for (const auto& entry : renderSources) {
|
||||
entry.second->onLowMemory();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderStyle::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 RenderStyle::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 RenderStyle::onTileChanged(RenderSource&, const OverscaledTileID&) {
|
||||
observer->onInvalidate();
|
||||
}
|
||||
|
||||
void RenderStyle::dumpDebugLogs() const {
|
||||
for (const auto& entry : renderSources) {
|
||||
entry.second->dumpDebugLogs();
|
||||
}
|
||||
|
||||
imageManager->dumpDebugLogs();
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -1,92 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/renderer/render_source.hpp>
|
||||
#include <mbgl/renderer/render_source_observer.hpp>
|
||||
#include <mbgl/renderer/render_layer.hpp>
|
||||
#include <mbgl/renderer/render_light.hpp>
|
||||
#include <mbgl/text/glyph_manager_observer.hpp>
|
||||
#include <mbgl/map/zoom_history.hpp>
|
||||
#include <mbgl/map/mode.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class FileSource;
|
||||
class GlyphManager;
|
||||
class ImageManager;
|
||||
class LineAtlas;
|
||||
class RenderData;
|
||||
class TransformState;
|
||||
class RenderedQueryOptions;
|
||||
class Scheduler;
|
||||
class UpdateParameters;
|
||||
class RenderStyleObserver;
|
||||
|
||||
namespace style {
|
||||
class Image;
|
||||
class Source;
|
||||
class Layer;
|
||||
} // namespace style
|
||||
|
||||
class RenderStyle : public GlyphManagerObserver,
|
||||
public RenderSourceObserver {
|
||||
public:
|
||||
RenderStyle(Scheduler&, FileSource&);
|
||||
~RenderStyle() final;
|
||||
|
||||
void setObserver(RenderStyleObserver*);
|
||||
void update(const UpdateParameters&);
|
||||
|
||||
bool isLoaded() const;
|
||||
bool hasTransitions() const;
|
||||
|
||||
RenderSource* getRenderSource(const std::string& id) const;
|
||||
|
||||
std::vector<const RenderLayer*> getRenderLayers() const;
|
||||
|
||||
RenderLayer* getRenderLayer(const std::string& id);
|
||||
const RenderLayer* getRenderLayer(const std::string& id) const;
|
||||
|
||||
const RenderLight& getRenderLight() const;
|
||||
|
||||
RenderData getRenderData(MapDebugOptions, float angle);
|
||||
|
||||
std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry,
|
||||
const TransformState& transformState,
|
||||
const RenderedQueryOptions& options) const;
|
||||
|
||||
void onLowMemory();
|
||||
|
||||
void dumpDebugLogs() const;
|
||||
|
||||
Scheduler& scheduler;
|
||||
FileSource& fileSource;
|
||||
std::unique_ptr<GlyphManager> glyphManager;
|
||||
std::unique_ptr<ImageManager> imageManager;
|
||||
std::unique_ptr<LineAtlas> lineAtlas;
|
||||
|
||||
private:
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
RenderStyleObserver* observer;
|
||||
ZoomHistory zoomHistory;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class RenderStyleObserver {
|
||||
public:
|
||||
virtual ~RenderStyleObserver() = default;
|
||||
virtual void onInvalidate() {}
|
||||
virtual void onResourceError(std::exception_ptr) {}
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -1,13 +1,37 @@
|
||||
#include <mbgl/renderer/renderer_impl.hpp>
|
||||
#include <mbgl/renderer/render_style.hpp>
|
||||
#include <mbgl/renderer/render_static_data.hpp>
|
||||
#include <mbgl/renderer/render_item.hpp>
|
||||
#include <mbgl/renderer/update_parameters.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_source.hpp>
|
||||
#include <mbgl/renderer/render_item.hpp>
|
||||
#include <mbgl/renderer/render_tile.hpp>
|
||||
#include <mbgl/renderer/layers/render_background_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_circle_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_custom_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_fill_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_line_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_raster_layer.hpp>
|
||||
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
|
||||
#include <mbgl/renderer/style_diff.hpp>
|
||||
#include <mbgl/renderer/query.hpp>
|
||||
#include <mbgl/renderer/backend_scope.hpp>
|
||||
#include <mbgl/renderer/image_manager.hpp>
|
||||
#include <mbgl/gl/debugging.hpp>
|
||||
#include <mbgl/geometry/line_atlas.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/source_impl.hpp>
|
||||
#include <mbgl/style/transition_options.hpp>
|
||||
#include <mbgl/sprite/sprite_loader.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 {
|
||||
|
||||
@@ -24,19 +48,30 @@ Renderer::Impl::Impl(RendererBackend& backend_,
|
||||
Scheduler& scheduler_,
|
||||
GLContextMode contextMode_,
|
||||
const optional<std::string> programCacheDir_)
|
||||
: backend(backend_)
|
||||
, observer(&nullObserver())
|
||||
, contextMode(contextMode_)
|
||||
, pixelRatio(pixelRatio_)
|
||||
, programCacheDir(programCacheDir_)
|
||||
, renderStyle(std::make_unique<RenderStyle>(scheduler_, fileSource_)) {
|
||||
|
||||
renderStyle->setObserver(this);
|
||||
: backend(backend_)
|
||||
, scheduler(scheduler_)
|
||||
, fileSource(fileSource_)
|
||||
, observer(&nullObserver())
|
||||
, contextMode(contextMode_)
|
||||
, pixelRatio(pixelRatio_)
|
||||
, programCacheDir(programCacheDir_)
|
||||
, glyphManager(std::make_unique<GlyphManager>(fileSource))
|
||||
, imageManager(std::make_unique<ImageManager>())
|
||||
, lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 }))
|
||||
, 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>()) {
|
||||
glyphManager->setObserver(this);
|
||||
}
|
||||
|
||||
Renderer::Impl::~Impl() {
|
||||
BackendScope guard { backend };
|
||||
renderStyle.reset();
|
||||
glyphManager.reset();
|
||||
imageManager.reset();
|
||||
lineAtlas.reset();
|
||||
renderSources.reset();
|
||||
renderLayers.reset();
|
||||
staticData.reset();
|
||||
};
|
||||
|
||||
@@ -50,7 +85,152 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
|
||||
|
||||
assert(BackendScope::exists());
|
||||
|
||||
renderStyle->update(updateParameters);
|
||||
const bool zoomChanged = zoomHistory.update(updateParameters.transformState.getZoom(), updateParameters.timePoint);
|
||||
|
||||
const TransitionParameters transitionParameters {
|
||||
updateParameters.timePoint,
|
||||
updateParameters.mode == MapMode::Continuous ? updateParameters.transitionOptions : TransitionOptions()
|
||||
};
|
||||
|
||||
const PropertyEvaluationParameters evaluationParameters {
|
||||
zoomHistory,
|
||||
updateParameters.timePoint,
|
||||
updateParameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero()
|
||||
};
|
||||
|
||||
const TileParameters tileParameters {
|
||||
updateParameters.pixelRatio,
|
||||
updateParameters.debugOptions,
|
||||
updateParameters.transformState,
|
||||
updateParameters.scheduler,
|
||||
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;
|
||||
|
||||
// Remove removed images from sprite atlas.
|
||||
for (const auto& entry : imageDiff.removed) {
|
||||
imageManager->removeImage(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) {
|
||||
imageManager->updateImage(entry.second.after);
|
||||
}
|
||||
|
||||
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) {
|
||||
renderLayers.emplace(entry.first, RenderLayer::create(entry.second));
|
||||
}
|
||||
|
||||
// Update render layers for changed layers.
|
||||
for (const auto& entry : layerDiff.changed) {
|
||||
renderLayers.at(entry.first)->setImpl(entry.second.after);
|
||||
}
|
||||
|
||||
// Update layers for class and zoom changes.
|
||||
for (const auto& entry : renderLayers) {
|
||||
RenderLayer& layer = *entry.second;
|
||||
const bool layerAdded = layerDiff.added.count(entry.first);
|
||||
const bool layerChanged = layerDiff.changed.count(entry.first);
|
||||
|
||||
if (layerAdded || layerChanged) {
|
||||
layer.transition(transitionParameters);
|
||||
}
|
||||
|
||||
if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) {
|
||||
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));
|
||||
}
|
||||
|
||||
// Update all sources.
|
||||
for (const auto& source : *sourceImpls) {
|
||||
std::vector<Immutable<Layer::Impl>> filteredLayers;
|
||||
bool needsRendering = false;
|
||||
bool needsRelayout = false;
|
||||
|
||||
for (const auto& layer : *layerImpls) {
|
||||
if (layer->type == LayerType::Background ||
|
||||
layer->type == LayerType::Custom ||
|
||||
layer->source != source->id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!needsRendering && getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) {
|
||||
needsRendering = true;
|
||||
}
|
||||
|
||||
if (!needsRelayout && (
|
||||
hasLayoutDifference(layerDiff, layer->id) ||
|
||||
!imageDiff.added.empty() ||
|
||||
!imageDiff.removed.empty() ||
|
||||
!imageDiff.changed.empty())) {
|
||||
needsRelayout = true;
|
||||
}
|
||||
|
||||
filteredLayers.push_back(layer);
|
||||
}
|
||||
|
||||
renderSources.at(source->id)->update(source,
|
||||
filteredLayers,
|
||||
needsRendering,
|
||||
needsRelayout,
|
||||
tileParameters);
|
||||
}
|
||||
|
||||
transformState = updateParameters.transformState;
|
||||
|
||||
if (!staticData) {
|
||||
@@ -63,12 +243,14 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
|
||||
contextMode,
|
||||
backend,
|
||||
updateParameters,
|
||||
*renderStyle,
|
||||
renderLight.getEvaluated(),
|
||||
*staticData,
|
||||
frameHistory
|
||||
frameHistory,
|
||||
*imageManager,
|
||||
*lineAtlas
|
||||
};
|
||||
|
||||
bool loaded = updateParameters.styleLoaded && renderStyle->isLoaded();
|
||||
bool loaded = updateParameters.styleLoaded && isLoaded();
|
||||
|
||||
if (updateParameters.mode == MapMode::Continuous) {
|
||||
if (renderState == RenderState::Never) {
|
||||
@@ -84,7 +266,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
|
||||
|
||||
observer->onDidFinishRenderingFrame(
|
||||
loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
|
||||
renderStyle->hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION)
|
||||
hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION)
|
||||
);
|
||||
|
||||
if (!loaded) {
|
||||
@@ -114,10 +296,109 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
|
||||
parameters.context.setDirtyState();
|
||||
}
|
||||
|
||||
RenderData renderData = renderStyle->getRenderData(parameters.debugOptions, parameters.state.getAngle());
|
||||
RenderData renderData;
|
||||
const std::vector<RenderItem>& order = renderData.order;
|
||||
const std::unordered_set<RenderSource*>& sources = renderData.sources;
|
||||
|
||||
for (const auto& entry : renderSources) {
|
||||
if (entry.second->isEnabled()) {
|
||||
renderData.sources.insert(entry.second.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& layerImpl : *layerImpls) {
|
||||
RenderLayer* layer = getRenderLayer(layerImpl->id);
|
||||
assert(layer);
|
||||
|
||||
if (!layer->needsRendering(zoomHistory.lastZoom)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) {
|
||||
if (parameters.debugOptions & MapDebugOptions::Overdraw) {
|
||||
// We want to skip glClear optimization in overdraw mode.
|
||||
renderData.order.emplace_back(*layer, nullptr);
|
||||
continue;
|
||||
}
|
||||
const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated;
|
||||
if (layerImpl.get() == layerImpls->at(0).get() && paint.get<BackgroundPattern>().from.empty()) {
|
||||
// This is a solid background. We can use glClear().
|
||||
renderData.backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
|
||||
} else {
|
||||
// This is a textured background, or not the bottommost layer. We need to render it with a quad.
|
||||
renderData.order.emplace_back(*layer, nullptr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (layer->is<RenderCustomLayer>()) {
|
||||
renderData.order.emplace_back(*layer, nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
RenderSource* source = getRenderSource(layer->baseImpl->source);
|
||||
if (!source) {
|
||||
Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool symbolLayer = layer->is<RenderSymbolLayer>();
|
||||
|
||||
auto sortedTiles = source->getRenderTiles();
|
||||
if (symbolLayer) {
|
||||
// Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn
|
||||
// on top of each other, with lower symbols being drawn on top of higher symbols.
|
||||
std::sort(sortedTiles.begin(), sortedTiles.end(), [&](const RenderTile& a, const RenderTile& b) {
|
||||
Point<float> pa(a.id.canonical.x, a.id.canonical.y);
|
||||
Point<float> pb(b.id.canonical.x, b.id.canonical.y);
|
||||
|
||||
auto par = util::rotate(pa, parameters.state.getAngle());
|
||||
auto pbr = util::rotate(pb, parameters.state.getAngle());
|
||||
|
||||
return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x);
|
||||
});
|
||||
} else {
|
||||
std::sort(sortedTiles.begin(), sortedTiles.end(),
|
||||
[](const auto& a, const auto& b) { return a.get().id < b.get().id; });
|
||||
}
|
||||
|
||||
std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
|
||||
for (auto& sortedTile : sortedTiles) {
|
||||
auto& tile = sortedTile.get();
|
||||
if (!tile.tile.isRenderable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We're not clipping symbol layers, so when we have both parents and children of symbol
|
||||
// layers, we drop all children in favor of their parent to avoid duplicate labels.
|
||||
// See https://github.com/mapbox/mapbox-gl-native/issues/2482
|
||||
if (symbolLayer) {
|
||||
bool skip = false;
|
||||
// Look back through the buckets we decided to render to find out whether there is
|
||||
// already a bucket from this layer that is a parent of this tile. Tiles are ordered
|
||||
// by zoom level when we obtain them from getTiles().
|
||||
for (auto it = sortedTilesForInsertion.rbegin();
|
||||
it != sortedTilesForInsertion.rend(); ++it) {
|
||||
if (tile.tile.id.isChildOf(it->get().tile.id)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto bucket = tile.tile.getBucket(*layer->baseImpl);
|
||||
if (bucket) {
|
||||
sortedTilesForInsertion.emplace_back(tile);
|
||||
tile.used = true;
|
||||
}
|
||||
}
|
||||
layer->setRenderTiles(std::move(sortedTilesForInsertion));
|
||||
renderData.order.emplace_back(*layer, source);
|
||||
}
|
||||
|
||||
frameHistory.record(parameters.timePoint,
|
||||
parameters.state.getZoom(),
|
||||
parameters.mapMode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Milliseconds(0));
|
||||
@@ -329,33 +610,134 @@ void Renderer::Impl::doRender(PaintParameters& parameters) {
|
||||
}
|
||||
|
||||
std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const {
|
||||
return renderStyle->queryRenderedFeatures(geometry, transformState, options);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> sourceIDs;
|
||||
for (const RenderLayer* layer : layers) {
|
||||
sourceIDs.emplace(layer->baseImpl->source);
|
||||
}
|
||||
|
||||
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);
|
||||
std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Feature> result;
|
||||
|
||||
if (resultsByLayer.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Combine all results based on the style layer order.
|
||||
for (const auto& layerImpl : *layerImpls) {
|
||||
const RenderLayer* layer = getRenderLayer(layerImpl->id);
|
||||
if (!layer->needsRendering(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::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
|
||||
const RenderSource* source = renderStyle->getRenderSource(sourceID);
|
||||
const RenderSource* source = getRenderSource(sourceID);
|
||||
if (!source) return {};
|
||||
|
||||
return source->querySourceFeatures(options);
|
||||
}
|
||||
|
||||
void Renderer::Impl::onInvalidate() {
|
||||
observer->onInvalidate();
|
||||
}
|
||||
|
||||
void Renderer::Impl::onResourceError(std::exception_ptr ptr) {
|
||||
observer->onResourceError(ptr);
|
||||
}
|
||||
|
||||
void Renderer::Impl::onLowMemory() {
|
||||
BackendScope guard { backend };
|
||||
backend.getContext().performCleanup();
|
||||
renderStyle->onLowMemory();
|
||||
for (const auto& entry : renderSources) {
|
||||
entry.second->onLowMemory();
|
||||
}
|
||||
observer->onInvalidate();
|
||||
}
|
||||
|
||||
void Renderer::Impl::dumDebugLogs() {
|
||||
renderStyle->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() const {
|
||||
if (renderLight.hasTransition()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& entry : renderLayers) {
|
||||
if (entry.second->hasTransition()) {
|
||||
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();
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
#include <mbgl/renderer/renderer_backend.hpp>
|
||||
#include <mbgl/renderer/renderer_observer.hpp>
|
||||
#include <mbgl/renderer/render_style_observer.hpp>
|
||||
#include <mbgl/renderer/render_source.hpp>
|
||||
#include <mbgl/renderer/render_source_observer.hpp>
|
||||
#include <mbgl/renderer/render_layer.hpp>
|
||||
#include <mbgl/renderer/render_light.hpp>
|
||||
#include <mbgl/renderer/frame_history.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/map/zoom_history.hpp>
|
||||
#include <mbgl/map/mode.hpp>
|
||||
#include <mbgl/text/glyph_manager_observer.hpp>
|
||||
#include <mbgl/style/image.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -15,10 +22,25 @@ namespace mbgl {
|
||||
|
||||
class UpdateParameters;
|
||||
class PaintParameters;
|
||||
class RenderStyle;
|
||||
class RenderStaticData;
|
||||
class RenderData;
|
||||
class RenderedQueryOptions;
|
||||
class SourceQueryOptions;
|
||||
|
||||
class Renderer::Impl : public RenderStyleObserver {
|
||||
class FileSource;
|
||||
class GlyphManager;
|
||||
class ImageManager;
|
||||
class LineAtlas;
|
||||
class Scheduler;
|
||||
|
||||
namespace style {
|
||||
class Image;
|
||||
class Source;
|
||||
class Layer;
|
||||
} // namespace style
|
||||
|
||||
class Renderer::Impl : public GlyphManagerObserver,
|
||||
public RenderSourceObserver{
|
||||
public:
|
||||
Impl(RendererBackend&, float pixelRatio_, FileSource&, Scheduler&, GLContextMode,
|
||||
const optional<std::string> programCacheDir);
|
||||
@@ -34,16 +56,30 @@ public:
|
||||
void onLowMemory();
|
||||
void dumDebugLogs();
|
||||
|
||||
// RenderStyleObserver implementation
|
||||
void onInvalidate() override;
|
||||
void onResourceError(std::exception_ptr) override;
|
||||
|
||||
private:
|
||||
void doRender(PaintParameters&);
|
||||
|
||||
bool isLoaded() const;
|
||||
bool hasTransitions() const;
|
||||
|
||||
RenderSource* getRenderSource(const std::string& id) const;
|
||||
|
||||
RenderLayer* getRenderLayer(const std::string& id);
|
||||
const RenderLayer* getRenderLayer(const std::string& id) 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;
|
||||
|
||||
friend class Renderer;
|
||||
|
||||
RendererBackend& backend;
|
||||
Scheduler& scheduler;
|
||||
FileSource& fileSource;
|
||||
|
||||
RendererObserver* observer;
|
||||
|
||||
const GLContextMode contextMode;
|
||||
@@ -58,10 +94,21 @@ private:
|
||||
|
||||
RenderState renderState = RenderState::Never;
|
||||
FrameHistory frameHistory;
|
||||
ZoomHistory zoomHistory;
|
||||
TransformState transformState;
|
||||
|
||||
std::unique_ptr<RenderStyle> renderStyle;
|
||||
std::unique_ptr<GlyphManager> glyphManager;
|
||||
std::unique_ptr<ImageManager> imageManager;
|
||||
std::unique_ptr<LineAtlas> lineAtlas;
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
Reference in New Issue
Block a user