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