summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/renderer')
-rw-r--r--src/mbgl/renderer/painter.cpp8
-rw-r--r--src/mbgl/renderer/painter.hpp1
-rw-r--r--src/mbgl/renderer/render_item.hpp4
-rw-r--r--src/mbgl/renderer/render_source.cpp26
-rw-r--r--src/mbgl/renderer/render_source.hpp87
-rw-r--r--src/mbgl/renderer/render_source_observer.hpp18
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp95
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.hpp59
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.cpp87
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.hpp55
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.cpp91
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.hpp55
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp263
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp87
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