diff options
Diffstat (limited to 'src/mbgl/renderer')
-rw-r--r-- | src/mbgl/renderer/painter.cpp | 8 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/render_item.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/renderer/render_source.cpp | 26 | ||||
-rw-r--r-- | src/mbgl/renderer/render_source.hpp | 87 | ||||
-rw-r--r-- | src/mbgl/renderer/render_source_observer.hpp | 18 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_geojson_source.cpp | 95 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_geojson_source.hpp | 59 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_raster_source.cpp | 87 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_raster_source.hpp | 55 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_vector_source.cpp | 91 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_vector_source.hpp | 55 | ||||
-rw-r--r-- | src/mbgl/renderer/tile_pyramid.cpp | 263 | ||||
-rw-r--r-- | src/mbgl/renderer/tile_pyramid.hpp | 87 |
14 files changed, 931 insertions, 5 deletions
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 36dd4a793f..01df326d95 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -1,6 +1,7 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/render_source.hpp> #include <mbgl/style/source.hpp> #include <mbgl/style/source_impl.hpp> @@ -13,6 +14,7 @@ #include <mbgl/style/style.hpp> #include <mbgl/style/layer_impl.hpp> +#include <mbgl/tile/tile.hpp> #include <mbgl/renderer/render_background_layer.hpp> #include <mbgl/renderer/render_custom_layer.hpp> #include <mbgl/style/layers/custom_layer_impl.hpp> @@ -148,7 +150,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp RenderData renderData = style.getRenderData(frame.debugOptions, state.getAngle()); const std::vector<RenderItem>& order = renderData.order; - const std::unordered_set<Source*>& sources = renderData.sources; + const std::unordered_set<RenderSource*>& sources = renderData.sources; // Update the default matrices to the current viewport dimensions. state.getProjMatrix(projMatrix); @@ -209,7 +211,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp // Update all clipping IDs. algorithm::ClipIDGenerator generator; for (const auto& source : sources) { - source->baseImpl->startRender(generator, projMatrix, nearClippedProjMatrix, state); + source->startRender(generator, projMatrix, nearClippedProjMatrix, state); } MBGL_DEBUG_GROUP(context, "clipping masks"); @@ -258,7 +260,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp // When only rendering layers via the stylesheet, it's possible that we don't // ever visit a tile during rendering. for (const auto& source : sources) { - source->baseImpl->finishRender(*this); + source->finishRender(*this); } } diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 7706d2d451..c7c8173d0d 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -54,6 +54,7 @@ class RenderBackgroundLayer; class Programs; class PaintParameters; +class TilePyramid; struct ClipID; diff --git a/src/mbgl/renderer/render_item.hpp b/src/mbgl/renderer/render_item.hpp index 01bb263d1e..787211c30a 100644 --- a/src/mbgl/renderer/render_item.hpp +++ b/src/mbgl/renderer/render_item.hpp @@ -8,11 +8,11 @@ namespace mbgl { class RenderLayer; +class RenderSource; class RenderTile; class Bucket; namespace style { -class Source; } // namespace style class RenderItem { @@ -29,7 +29,7 @@ public: class RenderData { public: Color backgroundColor; - std::unordered_set<style::Source*> sources; + std::unordered_set<RenderSource*> sources; std::vector<RenderItem> order; }; diff --git a/src/mbgl/renderer/render_source.cpp b/src/mbgl/renderer/render_source.cpp new file mode 100644 index 0000000000..643d92fe81 --- /dev/null +++ b/src/mbgl/renderer/render_source.cpp @@ -0,0 +1,26 @@ +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/render_source_observer.hpp> +#include <mbgl/tile/tile.hpp> + +namespace mbgl { + +static RenderSourceObserver nullObserver; + +RenderSource::RenderSource(const style::Source::Impl& impl) + : baseImpl(impl), + observer(&nullObserver) { +} + +void RenderSource::setObserver(RenderSourceObserver* observer_) { + observer = observer_; +} + +void RenderSource::onTileChanged(Tile& tile) { + observer->onTileChanged(*this, tile.id); +} + +void RenderSource::onTileError(Tile& tile, std::exception_ptr error) { + observer->onTileError(*this, tile.id, error); +} + +} diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp new file mode 100644 index 0000000000..5d93ae49d6 --- /dev/null +++ b/src/mbgl/renderer/render_source.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include <mbgl/tile/tile_id.hpp> +#include <mbgl/tile/tile_observer.hpp> +#include <mbgl/util/mat4.hpp> +#include <mbgl/util/geo.hpp> +#include <mbgl/util/feature.hpp> +#include <mbgl/style/source_impl.hpp> + +#include <unordered_map> +#include <vector> +#include <map> +#include <memory> + +namespace mbgl { + +class Painter; +class TransformState; +class RenderTile; +class RenderedQueryOptions; +class SourceQueryOptions; +class Tile; +class RenderSourceObserver; + +namespace algorithm { +class ClipIDGenerator; +} // namespace algorithm + +namespace style { +class UpdateParameters; +} // namespace style + +class RenderSource : protected TileObserver { +public: + RenderSource(const style::Source::Impl&); + virtual ~RenderSource() = default; + + virtual bool isLoaded() const = 0; + + // Called when the camera has changed. May load new tiles, unload obsolete tiles, or + // trigger re-placement of existing complete tiles. + virtual void updateTiles(const style::UpdateParameters&) = 0; + + // Removes all tiles (by putting them into the cache). + virtual void removeTiles() = 0; + + // Remove all tiles and clear the cache. + virtual void invalidateTiles() = 0; + + // Request that all loaded tiles re-run the layout operation on the existing source + // data with fresh style information. + virtual void reloadTiles() = 0; + + virtual void startRender(algorithm::ClipIDGenerator&, + const mat4& projMatrix, + const mat4& clipMatrix, + const TransformState&) = 0; + virtual void finishRender(Painter&) = 0; + + virtual std::map<UnwrappedTileID, RenderTile>& getRenderTiles() = 0; + + virtual std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const = 0; + + virtual std::vector<Feature> + querySourceFeatures(const SourceQueryOptions&) const = 0; + + virtual void setCacheSize(size_t) = 0; + virtual void onLowMemory() = 0; + + virtual void dumpDebugLogs() const = 0; + + void setObserver(RenderSourceObserver*); + + const style::Source::Impl& baseImpl; + bool enabled = false; + +protected: + RenderSourceObserver* observer; + + void onTileChanged(Tile&) final; + void onTileError(Tile&, std::exception_ptr) final; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_source_observer.hpp b/src/mbgl/renderer/render_source_observer.hpp new file mode 100644 index 0000000000..792a18db2b --- /dev/null +++ b/src/mbgl/renderer/render_source_observer.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <exception> + +namespace mbgl { + +class RenderSource; +class OverscaledTileID; + +class RenderSourceObserver { +public: + virtual ~RenderSourceObserver() = default; + + virtual void onTileChanged(RenderSource&, const OverscaledTileID&) {} + virtual void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) {} +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp new file mode 100644 index 0000000000..7e36b44ea4 --- /dev/null +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -0,0 +1,95 @@ +#include <mbgl/renderer/sources/render_geojson_source.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/tile/geojson_tile.hpp> + +#include <mbgl/algorithm/generate_clip_ids.hpp> +#include <mbgl/algorithm/generate_clip_ids_impl.hpp> + +namespace mbgl { + +using namespace style; + +RenderGeoJSONSource::RenderGeoJSONSource(const style::GeoJSONSource::Impl& impl_) + : RenderSource(impl_), + impl(impl_) { + tilePyramid.setObserver(this); +} + +bool RenderGeoJSONSource::isLoaded() const { + return tilePyramid.isLoaded(); +} + +void RenderGeoJSONSource::invalidateTiles() { + tilePyramid.invalidateTiles(); +} + +void RenderGeoJSONSource::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) { + generator.update(tilePyramid.getRenderTiles()); + tilePyramid.startRender(projMatrix, clipMatrix, transform); +} + +void RenderGeoJSONSource::finishRender(Painter& painter) { + tilePyramid.finishRender(painter); +} + +std::map<UnwrappedTileID, RenderTile>& RenderGeoJSONSource::getRenderTiles() { + return tilePyramid.getRenderTiles(); +} + +void RenderGeoJSONSource::updateTiles(const UpdateParameters& parameters) { + GeoJSONData* data_ = impl.getData(); + + if (!data_) { + return; + } + + if (data_ != data) { + data = data_; + tilePyramid.cache.clear(); + + for (auto const& item : tilePyramid.tiles) { + static_cast<GeoJSONTile*>(item.second.get())->updateData(data->getTile(item.first.canonical)); + } + } + + tilePyramid.updateTiles(parameters, + SourceType::GeoJSON, + util::tileSize, + impl.getZoomRange(), + [&] (const OverscaledTileID& tileID) { + return std::make_unique<GeoJSONTile>(tileID, impl.id, parameters, data->getTile(tileID.canonical)); + }); +} + +void RenderGeoJSONSource::removeTiles() { + tilePyramid.removeTiles(); +} + +void RenderGeoJSONSource::reloadTiles() { + tilePyramid.reloadTiles(); +} + +std::unordered_map<std::string, std::vector<Feature>> +RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const { + return tilePyramid.queryRenderedFeatures(geometry, transformState, options); +} + +std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryOptions& options) const { + return tilePyramid.querySourceFeatures(options); +} + +void RenderGeoJSONSource::setCacheSize(size_t size) { + tilePyramid.setCacheSize(size); +} + +void RenderGeoJSONSource::onLowMemory() { + tilePyramid.onLowMemory(); +} + +void RenderGeoJSONSource::dumpDebugLogs() const { + tilePyramid.dumpDebugLogs(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp new file mode 100644 index 0000000000..3476b63afd --- /dev/null +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/tile_pyramid.hpp> +#include <mbgl/style/sources/geojson_source_impl.hpp> + +namespace mbgl { + +namespace style { +class GeoJSONData; +} // namespace style + +class RenderGeoJSONSource : public RenderSource { +public: + RenderGeoJSONSource(const style::GeoJSONSource::Impl&); + + bool isLoaded() const final; + + // Called when the camera has changed. May load new tiles, unload obsolete tiles, or + // trigger re-placement of existing complete tiles. + void updateTiles(const style::UpdateParameters&) final; + + // Removes all tiles (by putting them into the cache). + void removeTiles() final; + + // Remove all tiles and clear the cache. + void invalidateTiles() final; + + // Request that all loaded tiles re-run the layout operation on the existing source + // data with fresh style information. + void reloadTiles() final; + + void startRender(algorithm::ClipIDGenerator&, + const mat4& projMatrix, + const mat4& clipMatrix, + const TransformState&) final; + void finishRender(Painter&) final; + + std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final; + + std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const final; + + std::vector<Feature> + querySourceFeatures(const SourceQueryOptions&) const final; + + void setCacheSize(size_t) final; + void onLowMemory() final; + void dumpDebugLogs() const final; + +private: + const style::GeoJSONSource::Impl& impl; + TilePyramid tilePyramid; + style::GeoJSONData* data; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp new file mode 100644 index 0000000000..75a2189053 --- /dev/null +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -0,0 +1,87 @@ +#include <mbgl/renderer/sources/render_raster_source.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/tile/raster_tile.hpp> + +namespace mbgl { + +using namespace style; + +RenderRasterSource::RenderRasterSource(const style::RasterSource::Impl& impl_) + : RenderSource(impl_), + impl(impl_) { + tilePyramid.setObserver(this); +} + +bool RenderRasterSource::isLoaded() const { + return tilePyramid.isLoaded(); +} + +void RenderRasterSource::invalidateTiles() { + tilePyramid.invalidateTiles(); +} + +void RenderRasterSource::startRender(algorithm::ClipIDGenerator&, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) { + tilePyramid.startRender(projMatrix, clipMatrix, transform); +} + +void RenderRasterSource::finishRender(Painter& painter) { + tilePyramid.finishRender(painter); +} + +std::map<UnwrappedTileID, RenderTile>& RenderRasterSource::getRenderTiles() { + return tilePyramid.getRenderTiles(); +} + +void RenderRasterSource::updateTiles(const UpdateParameters& parameters) { + optional<Tileset> tileset = impl.getTileset(); + + if (!tileset) { + return; + } + + if (tileURLTemplates != tileset->tiles) { + tileURLTemplates = tileset->tiles; + tilePyramid.invalidateTiles(); + } + + tilePyramid.updateTiles(parameters, + SourceType::Raster, + impl.getTileSize(), + tileset->zoomRange, + [&] (const OverscaledTileID& tileID) { + return std::make_unique<RasterTile>(tileID, parameters, *tileset); + }); +} + +void RenderRasterSource::removeTiles() { + tilePyramid.removeTiles(); +} + +void RenderRasterSource::reloadTiles() { + tilePyramid.reloadTiles(); +} + +std::unordered_map<std::string, std::vector<Feature>> +RenderRasterSource::queryRenderedFeatures(const ScreenLineString&, + const TransformState&, + const RenderedQueryOptions&) const { + return {}; +} + +std::vector<Feature> RenderRasterSource::querySourceFeatures(const SourceQueryOptions&) const { + return {}; +} + +void RenderRasterSource::setCacheSize(size_t size) { + tilePyramid.setCacheSize(size); +} + +void RenderRasterSource::onLowMemory() { + tilePyramid.onLowMemory(); +} + +void RenderRasterSource::dumpDebugLogs() const { + tilePyramid.dumpDebugLogs(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp new file mode 100644 index 0000000000..6b95be363f --- /dev/null +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/tile_pyramid.hpp> +#include <mbgl/style/sources/raster_source_impl.hpp> + +namespace mbgl { + +class RenderRasterSource : public RenderSource { +public: + RenderRasterSource(const style::RasterSource::Impl&); + + bool isLoaded() const final; + + // Called when the camera has changed. May load new tiles, unload obsolete tiles, or + // trigger re-placement of existing complete tiles. + void updateTiles(const style::UpdateParameters&) final; + + // Removes all tiles (by putting them into the cache). + void removeTiles() final; + + // Remove all tiles and clear the cache. + void invalidateTiles() final; + + // Request that all loaded tiles re-run the layout operation on the existing source + // data with fresh style information. + void reloadTiles() final; + + void startRender(algorithm::ClipIDGenerator&, + const mat4& projMatrix, + const mat4& clipMatrix, + const TransformState&) final; + void finishRender(Painter&) final; + + std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final; + + std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const final; + + std::vector<Feature> + querySourceFeatures(const SourceQueryOptions&) const final; + + void setCacheSize(size_t) final; + void onLowMemory() final; + void dumpDebugLogs() const final; + +private: + const style::RasterSource::Impl& impl; + TilePyramid tilePyramid; + optional<std::vector<std::string>> tileURLTemplates; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp new file mode 100644 index 0000000000..3d7e09fd2a --- /dev/null +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -0,0 +1,91 @@ +#include <mbgl/renderer/sources/render_vector_source.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/tile/vector_tile.hpp> + +#include <mbgl/algorithm/generate_clip_ids.hpp> +#include <mbgl/algorithm/generate_clip_ids_impl.hpp> + +namespace mbgl { + +using namespace style; + +RenderVectorSource::RenderVectorSource(const style::VectorSource::Impl& impl_) + : RenderSource(impl_), + impl(impl_) { + tilePyramid.setObserver(this); +} + +bool RenderVectorSource::isLoaded() const { + return tilePyramid.isLoaded(); +} + +void RenderVectorSource::invalidateTiles() { + tilePyramid.invalidateTiles(); +} + +void RenderVectorSource::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) { + generator.update(tilePyramid.getRenderTiles()); + tilePyramid.startRender(projMatrix, clipMatrix, transform); +} + +void RenderVectorSource::finishRender(Painter& painter) { + tilePyramid.finishRender(painter); +} + +std::map<UnwrappedTileID, RenderTile>& RenderVectorSource::getRenderTiles() { + return tilePyramid.getRenderTiles(); +} + +void RenderVectorSource::updateTiles(const UpdateParameters& parameters) { + optional<Tileset> tileset = impl.getTileset(); + + if (!tileset) { + return; + } + + if (tileURLTemplates != tileset->tiles) { + tileURLTemplates = tileset->tiles; + tilePyramid.invalidateTiles(); + } + + tilePyramid.updateTiles(parameters, + SourceType::Vector, + util::tileSize, + tileset->zoomRange, + [&] (const OverscaledTileID& tileID) { + return std::make_unique<VectorTile>(tileID, impl.id, parameters, *tileset); + }); +} + +void RenderVectorSource::removeTiles() { + tilePyramid.removeTiles(); +} + +void RenderVectorSource::reloadTiles() { + tilePyramid.reloadTiles(); +} + +std::unordered_map<std::string, std::vector<Feature>> +RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const { + return tilePyramid.queryRenderedFeatures(geometry, transformState, options); +} + +std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOptions& options) const { + return tilePyramid.querySourceFeatures(options); +} + +void RenderVectorSource::setCacheSize(size_t size) { + tilePyramid.setCacheSize(size); +} + +void RenderVectorSource::onLowMemory() { + tilePyramid.onLowMemory(); +} + +void RenderVectorSource::dumpDebugLogs() const { + tilePyramid.dumpDebugLogs(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp new file mode 100644 index 0000000000..0f40c14cf5 --- /dev/null +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/tile_pyramid.hpp> +#include <mbgl/style/sources/vector_source_impl.hpp> + +namespace mbgl { + +class RenderVectorSource : public RenderSource { +public: + RenderVectorSource(const style::VectorSource::Impl&); + + bool isLoaded() const final; + + // Called when the camera has changed. May load new tiles, unload obsolete tiles, or + // trigger re-placement of existing complete tiles. + void updateTiles(const style::UpdateParameters&) final; + + // Removes all tiles (by putting them into the cache). + void removeTiles() final; + + // Remove all tiles and clear the cache. + void invalidateTiles() final; + + // Request that all loaded tiles re-run the layout operation on the existing source + // data with fresh style information. + void reloadTiles() final; + + void startRender(algorithm::ClipIDGenerator&, + const mat4& projMatrix, + const mat4& clipMatrix, + const TransformState&) final; + void finishRender(Painter&) final; + + std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final; + + std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const final; + + std::vector<Feature> + querySourceFeatures(const SourceQueryOptions&) const final; + + void setCacheSize(size_t) final; + void onLowMemory() final; + void dumpDebugLogs() const final; + +private: + const style::VectorSource::Impl& impl; + TilePyramid tilePyramid; + optional<std::vector<std::string>> tileURLTemplates; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp new file mode 100644 index 0000000000..130b9dc5b6 --- /dev/null +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -0,0 +1,263 @@ +#include <mbgl/renderer/tile_pyramid.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/painter.hpp> +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/style/update_parameters.hpp> +#include <mbgl/map/transform.hpp> +#include <mbgl/map/query.hpp> +#include <mbgl/text/placement_config.hpp> +#include <mbgl/math/clamp.hpp> +#include <mbgl/util/tile_cover.hpp> +#include <mbgl/util/enum.hpp> +#include <mbgl/util/logging.hpp> + +#include <mbgl/algorithm/update_renderables.hpp> + +#include <mapbox/geometry/envelope.hpp> + +#include <algorithm> + +namespace mbgl { + +using namespace style; + +static TileObserver nullObserver; + +TilePyramid::TilePyramid() + : observer(&nullObserver) { +} + +TilePyramid::~TilePyramid() = default; + +bool TilePyramid::isLoaded() const { + for (const auto& pair : tiles) { + if (!pair.second->isComplete()) { + return false; + } + } + + return true; +} + +void TilePyramid::invalidateTiles() { + tiles.clear(); + renderTiles.clear(); + cache.clear(); +} + +void TilePyramid::startRender(const mat4& projMatrix, + const mat4& clipMatrix, + const TransformState& transform) { + for (auto& pair : renderTiles) { + auto& tile = pair.second; + tile.calculateMatrices(projMatrix, clipMatrix, transform); + } +} + +void TilePyramid::finishRender(Painter& painter) { + for (auto& pair : renderTiles) { + auto& tile = pair.second; + if (tile.used) { + painter.renderTileDebug(tile); + } + } +} + +std::map<UnwrappedTileID, RenderTile>& TilePyramid::getRenderTiles() { + return renderTiles; +} + +void TilePyramid::updateTiles(const UpdateParameters& parameters, + const SourceType type, + const uint16_t tileSize, + const Range<uint8_t> zoomRange, + std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile) { + // Determine the overzooming/underzooming amounts and required tiles. + int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize); + int32_t tileZoom = overscaledZoom; + + std::vector<UnwrappedTileID> idealTiles; + if (overscaledZoom >= zoomRange.min) { + int32_t idealZoom = std::min<int32_t>(zoomRange.max, overscaledZoom); + + // Make sure we're not reparsing overzoomed raster tiles. + if (type == SourceType::Raster) { + tileZoom = idealZoom; + } + + idealTiles = util::tileCover(parameters.transformState, idealZoom); + } + + // Stores a list of all the tiles that we're definitely going to retain. There are two + // kinds of tiles we need: the ideal tiles determined by the tile cover. They may not yet be in + // use because they're still loading. In addition to that, we also need to retain all tiles that + // we're actively using, e.g. as a replacement for tile that aren't loaded yet. + std::set<OverscaledTileID> retain; + + auto retainTileFn = [&](Tile& tile, Resource::Necessity necessity) -> void { + retain.emplace(tile.id); + tile.setNecessity(necessity); + }; + auto getTileFn = [&](const OverscaledTileID& tileID) -> Tile* { + auto it = tiles.find(tileID); + return it == tiles.end() ? nullptr : it->second.get(); + }; + auto createTileFn = [&](const OverscaledTileID& tileID) -> Tile* { + std::unique_ptr<Tile> tile = cache.get(tileID); + if (!tile) { + tile = createTile(tileID); + if (tile) { + tile->setObserver(observer); + } + } + if (!tile) { + return nullptr; + } + return tiles.emplace(tileID, std::move(tile)).first->second.get(); + }; + auto renderTileFn = [&](const UnwrappedTileID& tileID, Tile& tile) { + renderTiles.emplace(tileID, RenderTile{ tileID, tile }); + }; + + renderTiles.clear(); + algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn, + idealTiles, zoomRange, tileZoom); + + if (type != SourceType::Annotations) { + size_t conservativeCacheSize = + std::max((float)parameters.transformState.getSize().width / tileSize, 1.0f) * + std::max((float)parameters.transformState.getSize().height / tileSize, 1.0f) * + (parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) * + 0.5; + cache.setSize(conservativeCacheSize); + } + + removeStaleTiles(retain); + + const PlacementConfig config { parameters.transformState.getAngle(), + parameters.transformState.getPitch(), + parameters.debugOptions & MapDebugOptions::Collision }; + + for (auto& pair : tiles) { + pair.second->setPlacementConfig(config); + } +} + +// Moves all tiles to the cache except for those specified in the retain set. +void TilePyramid::removeStaleTiles(const std::set<OverscaledTileID>& retain) { + // Remove stale tiles. This goes through the (sorted!) tiles map and retain set in lockstep + // and removes items from tiles that don't have the corresponding key in the retain set. + auto tilesIt = tiles.begin(); + auto retainIt = retain.begin(); + while (tilesIt != tiles.end()) { + if (retainIt == retain.end() || tilesIt->first < *retainIt) { + tilesIt->second->setNecessity(Tile::Necessity::Optional); + cache.add(tilesIt->first, std::move(tilesIt->second)); + tiles.erase(tilesIt++); + } else { + if (!(*retainIt < tilesIt->first)) { + ++tilesIt; + } + ++retainIt; + } + } +} + +void TilePyramid::removeTiles() { + renderTiles.clear(); + if (!tiles.empty()) { + removeStaleTiles({}); + } +} + +void TilePyramid::reloadTiles() { + cache.clear(); + + for (auto& pair : tiles) { + pair.second->redoLayout(); + } +} + +std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const { + std::unordered_map<std::string, std::vector<Feature>> result; + if (renderTiles.empty() || geometry.empty()) { + return result; + } + + LineString<double> queryGeometry; + + for (const auto& p : geometry) { + queryGeometry.push_back(TileCoordinate::fromScreenCoordinate( + transformState, 0, { p.x, transformState.getSize().height - p.y }).p); + } + + mapbox::geometry::box<double> box = mapbox::geometry::envelope(queryGeometry); + + + auto sortRenderTiles = [](const RenderTile& a, const RenderTile& b) { + return std::tie(a.id.canonical.z, a.id.canonical.y, a.id.wrap, a.id.canonical.x) < + std::tie(b.id.canonical.z, b.id.canonical.y, b.id.wrap, b.id.canonical.x); + }; + std::vector<std::reference_wrapper<const RenderTile>> sortedTiles; + std::transform(renderTiles.cbegin(), renderTiles.cend(), std::back_inserter(sortedTiles), + [](const auto& pair) { return std::ref(pair.second); }); + std::sort(sortedTiles.begin(), sortedTiles.end(), sortRenderTiles); + + for (const auto& renderTileRef : sortedTiles) { + const RenderTile& renderTile = renderTileRef.get(); + GeometryCoordinate tileSpaceBoundsMin = TileCoordinate::toGeometryCoordinate(renderTile.id, box.min); + if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT) { + continue; + } + + GeometryCoordinate tileSpaceBoundsMax = TileCoordinate::toGeometryCoordinate(renderTile.id, box.max); + if (tileSpaceBoundsMax.x < 0 || tileSpaceBoundsMax.y < 0) { + continue; + } + + GeometryCoordinates tileSpaceQueryGeometry; + tileSpaceQueryGeometry.reserve(queryGeometry.size()); + for (const auto& c : queryGeometry) { + tileSpaceQueryGeometry.push_back(TileCoordinate::toGeometryCoordinate(renderTile.id, c)); + } + + renderTile.tile.queryRenderedFeatures(result, + tileSpaceQueryGeometry, + transformState, + options); + } + + return result; +} + +std::vector<Feature> TilePyramid::querySourceFeatures(const SourceQueryOptions& options) const { + std::vector<Feature> result; + + for (const auto& pair : tiles) { + pair.second->querySourceFeatures(result, options); + } + + return result; +} + +void TilePyramid::setCacheSize(size_t size) { + cache.setSize(size); +} + +void TilePyramid::onLowMemory() { + cache.clear(); +} + +void TilePyramid::setObserver(TileObserver* observer_) { + observer = observer_; +} + +void TilePyramid::dumpDebugLogs() const { + for (const auto& pair : tiles) { + pair.second->dumpDebugLogs(); + } +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp new file mode 100644 index 0000000000..a38a21dd88 --- /dev/null +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include <mbgl/tile/tile_id.hpp> +#include <mbgl/tile/tile_observer.hpp> +#include <mbgl/tile/tile.hpp> +#include <mbgl/tile/tile_cache.hpp> +#include <mbgl/style/types.hpp> + +#include <mbgl/util/mat4.hpp> +#include <mbgl/util/feature.hpp> +#include <mbgl/util/range.hpp> + +#include <memory> +#include <unordered_map> +#include <vector> +#include <map> + +namespace mbgl { + +class Painter; +class TransformState; +class RenderTile; +class RenderedQueryOptions; +class SourceQueryOptions; + +namespace style { +class UpdateParameters; +} // namespace style + +class TilePyramid { +public: + TilePyramid(); + ~TilePyramid(); + + bool isLoaded() const; + + // Called when the camera has changed. May load new tiles, unload obsolete tiles, or + // trigger re-placement of existing complete tiles. + void updateTiles(const style::UpdateParameters&, + SourceType type, + uint16_t tileSize, + Range<uint8_t> zoomRange, + std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile); + + // Removes all tiles (by putting them into the cache). + void removeTiles(); + + // Remove all tiles and clear the cache. + void invalidateTiles(); + + // Request that all loaded tiles re-run the layout operation on the existing source + // data with fresh style information. + void reloadTiles(); + + void startRender(const mat4& projMatrix, + const mat4& clipMatrix, + const TransformState&); + void finishRender(Painter&); + + std::map<UnwrappedTileID, RenderTile>& getRenderTiles(); + + std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const; + + std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const; + + void setCacheSize(size_t); + void onLowMemory(); + + void setObserver(TileObserver*); + void dumpDebugLogs() const; + + bool enabled = false; + + void removeStaleTiles(const std::set<OverscaledTileID>&); + + std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles; + TileCache cache; + + std::map<UnwrappedTileID, RenderTile> renderTiles; + + TileObserver* observer = nullptr; +}; + +} // namespace mbgl |