1 #include <mbgl/tile/geometry_tile.hpp>
2 #include <mbgl/tile/geometry_tile_worker.hpp>
3 #include <mbgl/tile/geometry_tile_data.hpp>
4 #include <mbgl/tile/tile_observer.hpp>
5 #include <mbgl/style/layer_impl.hpp>
6 #include <mbgl/style/layers/background_layer.hpp>
7 #include <mbgl/style/layers/custom_layer.hpp>
8 #include <mbgl/renderer/tile_parameters.hpp>
9 #include <mbgl/renderer/layers/render_background_layer.hpp>
10 #include <mbgl/renderer/layers/render_custom_layer.hpp>
11 #include <mbgl/renderer/layers/render_symbol_layer.hpp>
12 #include <mbgl/renderer/buckets/symbol_bucket.hpp>
13 #include <mbgl/renderer/query.hpp>
14 #include <mbgl/text/glyph_atlas.hpp>
15 #include <mbgl/renderer/image_atlas.hpp>
16 #include <mbgl/storage/file_source.hpp>
17 #include <mbgl/geometry/feature_index.hpp>
18 #include <mbgl/map/transform_state.hpp>
19 #include <mbgl/util/logging.hpp>
20 #include <mbgl/actor/scheduler.hpp>
21
22 #include <iostream>
23
24 namespace mbgl {
25
26 using namespace style;
27
28 /*
29 Correlation between GeometryTile and GeometryTileWorker is safeguarded by two
30 correlation schemes:
31
32 GeometryTile's 'correlationID' is used for ensuring the tile will be flagged
33 as non-pending only when the placement coming from the last operation (as in
34 'setData', 'setLayers', 'setShowCollisionBoxes') occurs. This is important for
35 still mode rendering as we want to render only when all layout and placement
36 operations are completed.
37
38 GeometryTileWorker's 'imageCorrelationID' is used for checking whether an
39 image request reply coming from `GeometryTile` is valid. Previous image
40 request replies are ignored as they result in incomplete placement attempts
41 that could flag the tile as non-pending too early.
42 */
43
GeometryTile(const OverscaledTileID & id_,std::string sourceID_,const TileParameters & parameters)44 GeometryTile::GeometryTile(const OverscaledTileID& id_,
45 std::string sourceID_,
46 const TileParameters& parameters)
47 : Tile(id_),
48 sourceID(std::move(sourceID_)),
49 mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())),
50 worker(parameters.workerScheduler,
51 ActorRef<GeometryTile>(*this, mailbox),
52 id_,
53 sourceID,
54 obsolete,
55 parameters.mode,
56 parameters.pixelRatio,
57 parameters.debugOptions & MapDebugOptions::Collision),
58 glyphManager(parameters.glyphManager),
59 imageManager(parameters.imageManager),
60 mode(parameters.mode),
61 showCollisionBoxes(parameters.debugOptions & MapDebugOptions::Collision) {
62 }
63
~GeometryTile()64 GeometryTile::~GeometryTile() {
65 glyphManager.removeRequestor(*this);
66 imageManager.removeRequestor(*this);
67 markObsolete();
68 }
69
cancel()70 void GeometryTile::cancel() {
71 markObsolete();
72 }
73
markObsolete()74 void GeometryTile::markObsolete() {
75 obsolete = true;
76 }
77
setError(std::exception_ptr err)78 void GeometryTile::setError(std::exception_ptr err) {
79 loaded = true;
80 observer->onTileError(*this, err);
81 }
82
setData(std::unique_ptr<const GeometryTileData> data_)83 void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) {
84 // Mark the tile as pending again if it was complete before to prevent signaling a complete
85 // state despite pending parse operations.
86 pending = true;
87
88 ++correlationID;
89 worker.self().invoke(&GeometryTileWorker::setData, std::move(data_), correlationID);
90 }
91
92
setLayers(const std::vector<Immutable<Layer::Impl>> & layers)93 void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers) {
94 // Mark the tile as pending again if it was complete before to prevent signaling a complete
95 // state despite pending parse operations.
96 pending = true;
97
98 std::vector<Immutable<Layer::Impl>> impls;
99
100 for (const auto& layer : layers) {
101 // Skip irrelevant layers.
102 if (layer->type == LayerType::Background ||
103 layer->type == LayerType::Custom ||
104 layer->source != sourceID ||
105 id.overscaledZ < std::floor(layer->minZoom) ||
106 id.overscaledZ >= std::ceil(layer->maxZoom) ||
107 layer->visibility == VisibilityType::None) {
108 continue;
109 }
110
111 impls.push_back(layer);
112 }
113
114 ++correlationID;
115 worker.self().invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID);
116 }
117
setShowCollisionBoxes(const bool showCollisionBoxes_)118 void GeometryTile::setShowCollisionBoxes(const bool showCollisionBoxes_) {
119 if (showCollisionBoxes != showCollisionBoxes_) {
120 showCollisionBoxes = showCollisionBoxes_;
121 ++correlationID;
122 worker.self().invoke(&GeometryTileWorker::setShowCollisionBoxes, showCollisionBoxes, correlationID);
123 }
124 }
125
onLayout(LayoutResult result,const uint64_t resultCorrelationID)126 void GeometryTile::onLayout(LayoutResult result, const uint64_t resultCorrelationID) {
127 loaded = true;
128 renderable = true;
129 if (resultCorrelationID == correlationID) {
130 pending = false;
131 }
132
133 buckets = std::move(result.buckets);
134
135 latestFeatureIndex = std::move(result.featureIndex);
136
137 if (result.glyphAtlasImage) {
138 glyphAtlasImage = std::move(*result.glyphAtlasImage);
139 }
140 if (result.iconAtlasImage) {
141 iconAtlasImage = std::move(*result.iconAtlasImage);
142 }
143
144 observer->onTileChanged(*this);
145 }
146
onError(std::exception_ptr err,const uint64_t resultCorrelationID)147 void GeometryTile::onError(std::exception_ptr err, const uint64_t resultCorrelationID) {
148 loaded = true;
149 if (resultCorrelationID == correlationID) {
150 pending = false;
151 }
152 observer->onTileError(*this, err);
153 }
154
onGlyphsAvailable(GlyphMap glyphs)155 void GeometryTile::onGlyphsAvailable(GlyphMap glyphs) {
156 worker.self().invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs));
157 }
158
getGlyphs(GlyphDependencies glyphDependencies)159 void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) {
160 glyphManager.getGlyphs(*this, std::move(glyphDependencies));
161 }
162
onImagesAvailable(ImageMap images,uint64_t imageCorrelationID)163 void GeometryTile::onImagesAvailable(ImageMap images, uint64_t imageCorrelationID) {
164 worker.self().invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), imageCorrelationID);
165 }
166
getImages(ImageRequestPair pair)167 void GeometryTile::getImages(ImageRequestPair pair) {
168 imageManager.getImages(*this, std::move(pair));
169 }
170
upload(gl::Context & context)171 void GeometryTile::upload(gl::Context& context) {
172 auto uploadFn = [&] (Bucket& bucket) {
173 if (bucket.needsUpload()) {
174 bucket.upload(context);
175 }
176 };
177
178 for (auto& entry : buckets) {
179 uploadFn(*entry.second);
180 }
181
182 if (glyphAtlasImage) {
183 glyphAtlasTexture = context.createTexture(*glyphAtlasImage, 0);
184 glyphAtlasImage = {};
185 }
186
187 if (iconAtlasImage) {
188 iconAtlasTexture = context.createTexture(*iconAtlasImage, 0);
189 iconAtlasImage = {};
190 }
191 }
192
getBucket(const Layer::Impl & layer) const193 Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const {
194 const auto it = buckets.find(layer.id);
195 if (it == buckets.end()) {
196 return nullptr;
197 }
198
199 assert(it->second);
200 return it->second.get();
201 }
202
getQueryPadding(const std::vector<const RenderLayer * > & layers)203 float GeometryTile::getQueryPadding(const std::vector<const RenderLayer*>& layers) {
204 float queryPadding = 0;
205 for (const RenderLayer* layer : layers) {
206 auto bucket = getBucket(*layer->baseImpl);
207 if (bucket && bucket->hasData()) {
208 queryPadding = std::max(queryPadding, bucket->getQueryRadius(*layer));
209 }
210 }
211 return queryPadding;
212 }
213
queryRenderedFeatures(std::unordered_map<std::string,std::vector<Feature>> & result,const GeometryCoordinates & queryGeometry,const TransformState & transformState,const std::vector<const RenderLayer * > & layers,const RenderedQueryOptions & options,const mat4 & projMatrix)214 void GeometryTile::queryRenderedFeatures(
215 std::unordered_map<std::string, std::vector<Feature>>& result,
216 const GeometryCoordinates& queryGeometry,
217 const TransformState& transformState,
218 const std::vector<const RenderLayer*>& layers,
219 const RenderedQueryOptions& options,
220 const mat4& projMatrix) {
221
222 if (!getData()) return;
223
224 const float queryPadding = getQueryPadding(layers);
225
226 mat4 posMatrix;
227 transformState.matrixFor(posMatrix, id.toUnwrapped());
228 matrix::multiply(posMatrix, projMatrix, posMatrix);
229
230 latestFeatureIndex->query(result,
231 queryGeometry,
232 transformState,
233 posMatrix,
234 util::tileSize * id.overscaleFactor(),
235 std::pow(2, transformState.getZoom() - id.overscaledZ),
236 options,
237 id.toUnwrapped(),
238 layers,
239 queryPadding * transformState.maxPitchScaleFactor());
240 }
241
querySourceFeatures(std::vector<Feature> & result,const SourceQueryOptions & options)242 void GeometryTile::querySourceFeatures(
243 std::vector<Feature>& result,
244 const SourceQueryOptions& options) {
245
246 // Data not yet available, or tile is empty
247 if (!getData()) {
248 return;
249 }
250
251 // No source layers, specified, nothing to do
252 if (!options.sourceLayers) {
253 Log::Warning(Event::General, "At least one sourceLayer required");
254 return;
255 }
256
257 for (auto sourceLayer : *options.sourceLayers) {
258 // Go throught all sourceLayers, if any
259 // to gather all the features
260 auto layer = getData()->getLayer(sourceLayer);
261
262 if (layer) {
263 auto featureCount = layer->featureCount();
264 for (std::size_t i = 0; i < featureCount; i++) {
265 auto feature = layer->getFeature(i);
266
267 // Apply filter, if any
268 if (options.filter && !(*options.filter)(style::expression::EvaluationContext { static_cast<float>(this->id.overscaledZ), feature.get() })) {
269 continue;
270 }
271
272 result.push_back(convertFeature(*feature, id.canonical));
273 }
274 }
275 }
276 }
277
holdForFade() const278 bool GeometryTile::holdForFade() const {
279 return mode == MapMode::Continuous &&
280 (fadeState == FadeState::NeedsFirstPlacement || fadeState == FadeState::NeedsSecondPlacement);
281 }
282
markRenderedIdeal()283 void GeometryTile::markRenderedIdeal() {
284 fadeState = FadeState::Loaded;
285 }
markRenderedPreviously()286 void GeometryTile::markRenderedPreviously() {
287 if (fadeState == FadeState::Loaded) {
288 fadeState = FadeState::NeedsFirstPlacement;
289 }
290 }
performedFadePlacement()291 void GeometryTile::performedFadePlacement() {
292 if (fadeState == FadeState::NeedsFirstPlacement) {
293 fadeState = FadeState::NeedsSecondPlacement;
294 } else if (fadeState == FadeState::NeedsSecondPlacement) {
295 fadeState = FadeState::CanRemove;
296 }
297 }
298
299 } // namespace mbgl
300