1 #include <mbgl/annotation/annotation_manager.hpp>
2 #include <mbgl/renderer/renderer_impl.hpp>
3 #include <mbgl/renderer/renderer_backend.hpp>
4 #include <mbgl/renderer/renderer_observer.hpp>
5 #include <mbgl/renderer/render_source.hpp>
6 #include <mbgl/renderer/render_layer.hpp>
7 #include <mbgl/renderer/render_static_data.hpp>
8 #include <mbgl/renderer/update_parameters.hpp>
9 #include <mbgl/renderer/paint_parameters.hpp>
10 #include <mbgl/renderer/transition_parameters.hpp>
11 #include <mbgl/renderer/property_evaluation_parameters.hpp>
12 #include <mbgl/renderer/tile_parameters.hpp>
13 #include <mbgl/renderer/render_tile.hpp>
14 #include <mbgl/renderer/layers/render_background_layer.hpp>
15 #include <mbgl/renderer/layers/render_custom_layer.hpp>
16 #include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
17 #include <mbgl/renderer/layers/render_heatmap_layer.hpp>
18 #include <mbgl/renderer/layers/render_hillshade_layer.hpp>
19 #include <mbgl/renderer/style_diff.hpp>
20 #include <mbgl/renderer/query.hpp>
21 #include <mbgl/renderer/backend_scope.hpp>
22 #include <mbgl/renderer/image_manager.hpp>
23 #include <mbgl/gl/debugging.hpp>
24 #include <mbgl/geometry/line_atlas.hpp>
25 #include <mbgl/style/source_impl.hpp>
26 #include <mbgl/style/transition_options.hpp>
27 #include <mbgl/text/glyph_manager.hpp>
28 #include <mbgl/tile/tile.hpp>
29 #include <mbgl/util/math.hpp>
30 #include <mbgl/util/string.hpp>
31 #include <mbgl/util/logging.hpp>
32
33 namespace mbgl {
34
35 using namespace style;
36
nullObserver()37 static RendererObserver& nullObserver() {
38 static RendererObserver observer;
39 return observer;
40 }
41
Impl(RendererBackend & backend_,float pixelRatio_,FileSource & fileSource_,Scheduler & scheduler_,GLContextMode contextMode_,const optional<std::string> programCacheDir_,const optional<std::string> localFontFamily_)42 Renderer::Impl::Impl(RendererBackend& backend_,
43 float pixelRatio_,
44 FileSource& fileSource_,
45 Scheduler& scheduler_,
46 GLContextMode contextMode_,
47 const optional<std::string> programCacheDir_,
48 const optional<std::string> localFontFamily_)
49 : backend(backend_)
50 , scheduler(scheduler_)
51 , fileSource(fileSource_)
52 , observer(&nullObserver())
53 , contextMode(contextMode_)
54 , pixelRatio(pixelRatio_)
55 , programCacheDir(programCacheDir_)
56 , glyphManager(std::make_unique<GlyphManager>(fileSource, std::make_unique<LocalGlyphRasterizer>(localFontFamily_)))
57 , imageManager(std::make_unique<ImageManager>())
58 , lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 }))
59 , imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>())
60 , sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>())
61 , layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>())
62 , renderLight(makeMutable<Light::Impl>())
63 , placement(std::make_unique<Placement>(TransformState{}, MapMode::Static)) {
64 glyphManager->setObserver(this);
65 }
66
~Impl()67 Renderer::Impl::~Impl() {
68 assert(BackendScope::exists());
69
70 if (contextLost) {
71 // Signal all RenderCustomLayers that the context was lost
72 // before cleaning up
73 for (const auto& entry : renderLayers) {
74 RenderLayer& layer = *entry.second;
75 if (layer.is<RenderCustomLayer>()) {
76 layer.as<RenderCustomLayer>()->markContextDestroyed();
77 }
78 }
79 }
80 };
81
setObserver(RendererObserver * observer_)82 void Renderer::Impl::setObserver(RendererObserver* observer_) {
83 observer = observer_ ? observer_ : &nullObserver();
84 }
85
render(const UpdateParameters & updateParameters)86 void Renderer::Impl::render(const UpdateParameters& updateParameters) {
87 if (updateParameters.mode != MapMode::Continuous) {
88 // Reset zoom history state.
89 zoomHistory.first = true;
90 }
91
92 assert(BackendScope::exists());
93
94 updateParameters.annotationManager.updateData();
95
96 const bool zoomChanged = zoomHistory.update(updateParameters.transformState.getZoom(), updateParameters.timePoint);
97
98 const TransitionParameters transitionParameters {
99 updateParameters.timePoint,
100 updateParameters.mode == MapMode::Continuous ? updateParameters.transitionOptions : TransitionOptions()
101 };
102
103 const PropertyEvaluationParameters evaluationParameters {
104 zoomHistory,
105 updateParameters.timePoint,
106 updateParameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero()
107 };
108
109 const TileParameters tileParameters {
110 updateParameters.pixelRatio,
111 updateParameters.debugOptions,
112 updateParameters.transformState,
113 scheduler,
114 fileSource,
115 updateParameters.mode,
116 updateParameters.annotationManager,
117 *imageManager,
118 *glyphManager,
119 updateParameters.prefetchZoomDelta
120 };
121
122 glyphManager->setURL(updateParameters.glyphURL);
123
124 // Update light.
125 const bool lightChanged = renderLight.impl != updateParameters.light;
126
127 if (lightChanged) {
128 renderLight.impl = updateParameters.light;
129 renderLight.transition(transitionParameters);
130 }
131
132 if (lightChanged || zoomChanged || renderLight.hasTransition()) {
133 renderLight.evaluate(evaluationParameters);
134 }
135
136
137 const ImageDifference imageDiff = diffImages(imageImpls, updateParameters.images);
138 imageImpls = updateParameters.images;
139
140 // Remove removed images from sprite atlas.
141 for (const auto& entry : imageDiff.removed) {
142 imageManager->removeImage(entry.first);
143 }
144
145 // Add added images to sprite atlas.
146 for (const auto& entry : imageDiff.added) {
147 imageManager->addImage(entry.second);
148 }
149
150 // Update changed images.
151 for (const auto& entry : imageDiff.changed) {
152 imageManager->updateImage(entry.second.after);
153 }
154
155 imageManager->setLoaded(updateParameters.spriteLoaded);
156
157
158 const LayerDifference layerDiff = diffLayers(layerImpls, updateParameters.layers);
159 layerImpls = updateParameters.layers;
160
161 // Remove render layers for removed layers.
162 for (const auto& entry : layerDiff.removed) {
163 renderLayers.erase(entry.first);
164 }
165
166 // Create render layers for newly added layers.
167 for (const auto& entry : layerDiff.added) {
168 renderLayers.emplace(entry.first, RenderLayer::create(entry.second));
169 }
170
171 // Update render layers for changed layers.
172 for (const auto& entry : layerDiff.changed) {
173 renderLayers.at(entry.first)->setImpl(entry.second.after);
174 }
175
176 // Update layers for class and zoom changes.
177 for (const auto& entry : renderLayers) {
178 RenderLayer& layer = *entry.second;
179 const bool layerAdded = layerDiff.added.count(entry.first);
180 const bool layerChanged = layerDiff.changed.count(entry.first);
181
182 if (layerAdded || layerChanged) {
183 layer.transition(transitionParameters);
184
185 if (layer.is<RenderHeatmapLayer>()) {
186 layer.as<RenderHeatmapLayer>()->updateColorRamp();
187 }
188 }
189
190 if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) {
191 layer.evaluate(evaluationParameters);
192 }
193 }
194
195
196 const SourceDifference sourceDiff = diffSources(sourceImpls, updateParameters.sources);
197 sourceImpls = updateParameters.sources;
198
199 // Remove render layers for removed sources.
200 for (const auto& entry : sourceDiff.removed) {
201 renderSources.erase(entry.first);
202 }
203
204 // Create render sources for newly added sources.
205 for (const auto& entry : sourceDiff.added) {
206 std::unique_ptr<RenderSource> renderSource = RenderSource::create(entry.second);
207 renderSource->setObserver(this);
208 renderSources.emplace(entry.first, std::move(renderSource));
209 }
210
211 const bool hasImageDiff = !(imageDiff.added.empty() && imageDiff.removed.empty() && imageDiff.changed.empty());
212
213 // Update all sources.
214 for (const auto& source : *sourceImpls) {
215 std::vector<Immutable<Layer::Impl>> filteredLayers;
216 bool needsRendering = false;
217 bool needsRelayout = false;
218
219 for (const auto& layer : *layerImpls) {
220 if (layer->type == LayerType::Background ||
221 layer->type == LayerType::Custom ||
222 layer->source != source->id) {
223 continue;
224 }
225
226 if (!needsRendering && getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) {
227 needsRendering = true;
228 }
229
230 if (!needsRelayout && (hasImageDiff || hasLayoutDifference(layerDiff, layer->id))) {
231 needsRelayout = true;
232 }
233
234 filteredLayers.push_back(layer);
235 }
236
237 renderSources.at(source->id)->update(source,
238 filteredLayers,
239 needsRendering,
240 needsRelayout,
241 tileParameters);
242 }
243
244 transformState = updateParameters.transformState;
245
246 if (!staticData) {
247 staticData = std::make_unique<RenderStaticData>(backend.getContext(), pixelRatio, programCacheDir);
248 }
249
250 PaintParameters parameters {
251 backend.getContext(),
252 pixelRatio,
253 contextMode,
254 backend,
255 updateParameters,
256 renderLight.getEvaluated(),
257 *staticData,
258 *imageManager,
259 *lineAtlas
260 };
261
262 bool loaded = updateParameters.styleLoaded && isLoaded();
263 if (updateParameters.mode != MapMode::Continuous && !loaded) {
264 return;
265 }
266
267 if (renderState == RenderState::Never) {
268 observer->onWillStartRenderingMap();
269 }
270
271 observer->onWillStartRenderingFrame();
272
273 backend.updateAssumedState();
274
275 if (parameters.contextMode == GLContextMode::Shared) {
276 parameters.context.setDirtyState();
277 }
278
279 Color backgroundColor;
280
281 class RenderItem {
282 public:
283 RenderLayer& layer;
284 RenderSource* source;
285 };
286
287 std::vector<RenderItem> order;
288
289 for (auto& layerImpl : *layerImpls) {
290 RenderLayer* layer = getRenderLayer(layerImpl->id);
291 assert(layer);
292
293 if (!parameters.staticData.has3D && (
294 layer->is<RenderFillExtrusionLayer>() ||
295 layer->is<RenderHillshadeLayer>() ||
296 layer->is<RenderHeatmapLayer>())) {
297
298 parameters.staticData.has3D = true;
299 }
300
301 if (!layer->needsRendering(zoomHistory.lastZoom)) {
302 continue;
303 }
304
305 if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) {
306 const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated;
307 if (parameters.contextMode == GLContextMode::Unique
308 && layerImpl.get() == layerImpls->at(0).get()
309 && paint.get<BackgroundPattern>().from.empty()) {
310 // This is a solid background. We can use glClear().
311 backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
312 } else {
313 // This is a textured background, or not the bottommost layer. We need to render it with a quad.
314 order.emplace_back(RenderItem { *layer, nullptr });
315 }
316 continue;
317 }
318
319 if (layer->is<RenderCustomLayer>()) {
320 order.emplace_back(RenderItem { *layer, nullptr });
321 continue;
322 }
323
324 RenderSource* source = getRenderSource(layer->baseImpl->source);
325 if (!source) {
326 Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str());
327 continue;
328 }
329
330 const bool symbolLayer = layer->is<RenderSymbolLayer>();
331
332 auto sortedTiles = source->getRenderTiles();
333 if (symbolLayer) {
334 // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn
335 // on top of each other, with lower symbols being drawn on top of higher symbols.
336 std::sort(sortedTiles.begin(), sortedTiles.end(), [&](const RenderTile& a, const RenderTile& b) {
337 Point<float> pa(a.id.canonical.x, a.id.canonical.y);
338 Point<float> pb(b.id.canonical.x, b.id.canonical.y);
339
340 auto par = util::rotate(pa, parameters.state.getAngle());
341 auto pbr = util::rotate(pb, parameters.state.getAngle());
342
343 return std::tie(b.id.canonical.z, par.y, par.x) < std::tie(a.id.canonical.z, pbr.y, pbr.x);
344 });
345 } else {
346 std::sort(sortedTiles.begin(), sortedTiles.end(),
347 [](const auto& a, const auto& b) { return a.get().id < b.get().id; });
348 // Don't render non-symbol layers for tiles that we're only holding on to for symbol fading
349 sortedTiles.erase(std::remove_if(sortedTiles.begin(), sortedTiles.end(),
350 [](const auto& tile) { return tile.get().tile.holdForFade(); }),
351 sortedTiles.end());
352 }
353
354 std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
355 for (auto& sortedTile : sortedTiles) {
356 auto& tile = sortedTile.get();
357 if (!tile.tile.isRenderable()) {
358 continue;
359 }
360
361 auto bucket = tile.tile.getBucket(*layer->baseImpl);
362 if (bucket) {
363 sortedTilesForInsertion.emplace_back(tile);
364 tile.used = true;
365
366 // We only need clipping when we're _not_ drawing a symbol layer.
367 if (!symbolLayer) {
368 tile.needsClipping = true;
369 }
370 }
371 }
372 layer->setRenderTiles(std::move(sortedTilesForInsertion));
373 order.emplace_back(RenderItem { *layer, source });
374 }
375
376 bool symbolBucketsChanged = false;
377 if (parameters.mapMode != MapMode::Continuous) {
378 // TODO: Think about right way for symbol index to handle still rendering
379 crossTileSymbolIndex.reset();
380 }
381 for (auto it = order.rbegin(); it != order.rend(); ++it) {
382 if (it->layer.is<RenderSymbolLayer>()) {
383 const float lng = parameters.state.getLatLng().longitude();
384 if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>(), lng)) symbolBucketsChanged = true;
385 }
386 }
387
388 bool placementChanged = false;
389 if (!placement->stillRecent(parameters.timePoint)) {
390 placementChanged = true;
391
392 auto newPlacement = std::make_unique<Placement>(parameters.state, parameters.mapMode);
393 std::set<std::string> usedSymbolLayers;
394 for (auto it = order.rbegin(); it != order.rend(); ++it) {
395 if (it->layer.is<RenderSymbolLayer>()) {
396 usedSymbolLayers.insert(it->layer.getID());
397 newPlacement->placeLayer(*it->layer.as<RenderSymbolLayer>(), parameters.projMatrix, parameters.debugOptions & MapDebugOptions::Collision);
398 }
399 }
400
401 newPlacement->commit(*placement, parameters.timePoint);
402 crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers);
403 placement = std::move(newPlacement);
404
405 updateFadingTiles();
406 } else {
407 placement->setStale();
408 }
409
410 parameters.symbolFadeChange = placement->symbolFadeChange(parameters.timePoint);
411
412 if (placementChanged || symbolBucketsChanged) {
413 for (auto it = order.rbegin(); it != order.rend(); ++it) {
414 if (it->layer.is<RenderSymbolLayer>()) {
415 placement->updateLayerOpacities(*it->layer.as<RenderSymbolLayer>());
416 }
417 }
418 }
419
420 // - UPLOAD PASS -------------------------------------------------------------------------------
421 // Uploads all required buffers and images before we do any actual rendering.
422 {
423 MBGL_DEBUG_GROUP(parameters.context, "upload");
424
425 parameters.imageManager.upload(parameters.context, 0);
426 parameters.lineAtlas.upload(parameters.context, 0);
427
428 // Update all clipping IDs + upload buckets.
429 for (const auto& entry : renderSources) {
430 if (entry.second->isEnabled()) {
431 entry.second->startRender(parameters);
432 }
433 }
434 }
435
436 // - 3D PASS -------------------------------------------------------------------------------------
437 // Renders any 3D layers bottom-to-top to unique FBOs with texture attachments, but share the same
438 // depth rbo between them.
439 if (parameters.staticData.has3D) {
440 parameters.staticData.backendSize = parameters.backend.getFramebufferSize();
441
442 MBGL_DEBUG_GROUP(parameters.context, "3d");
443 parameters.pass = RenderPass::Pass3D;
444
445 if (!parameters.staticData.depthRenderbuffer ||
446 parameters.staticData.depthRenderbuffer->size != parameters.staticData.backendSize) {
447 parameters.staticData.depthRenderbuffer =
448 parameters.context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(parameters.staticData.backendSize);
449 }
450 parameters.staticData.depthRenderbuffer->shouldClear(true);
451
452 uint32_t i = static_cast<uint32_t>(order.size()) - 1;
453 for (auto it = order.begin(); it != order.end(); ++it, --i) {
454 parameters.currentLayer = i;
455 if (it->layer.hasRenderPass(parameters.pass)) {
456 MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
457 it->layer.render(parameters, it->source);
458 }
459 }
460 }
461
462 // - CLEAR -------------------------------------------------------------------------------------
463 // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any
464 // tiles whatsoever.
465 {
466 using namespace gl::value;
467
468 MBGL_DEBUG_GROUP(parameters.context, "clear");
469 parameters.backend.bind();
470 if (parameters.debugOptions & MapDebugOptions::Overdraw) {
471 parameters.context.clear(Color::black(), ClearDepth::Default, ClearStencil::Default);
472 } else if (parameters.contextMode == GLContextMode::Shared) {
473 parameters.context.clear({}, ClearDepth::Default, ClearStencil::Default);
474 } else {
475 parameters.context.clear(backgroundColor, ClearDepth::Default, ClearStencil::Default);
476 }
477 }
478
479 // - CLIPPING MASKS ----------------------------------------------------------------------------
480 // Draws the clipping masks to the stencil buffer.
481 {
482 MBGL_DEBUG_GROUP(parameters.context, "clipping masks");
483
484 static const Properties<>::PossiblyEvaluated properties {};
485 static const ClippingMaskProgram::PaintPropertyBinders paintAttributeData(properties, 0);
486
487 for (const auto& clipID : parameters.clipIDGenerator.getClipIDs()) {
488 auto& program = parameters.staticData.programs.clippingMask;
489
490 program.draw(
491 parameters.context,
492 gl::Triangles(),
493 gl::DepthMode::disabled(),
494 gl::StencilMode {
495 gl::StencilMode::Always(),
496 static_cast<int32_t>(clipID.second.reference.to_ulong()),
497 0b11111111,
498 gl::StencilMode::Keep,
499 gl::StencilMode::Keep,
500 gl::StencilMode::Replace
501 },
502 gl::ColorMode::disabled(),
503 parameters.staticData.quadTriangleIndexBuffer,
504 parameters.staticData.tileTriangleSegments,
505 program.computeAllUniformValues(
506 ClippingMaskProgram::UniformValues {
507 uniforms::u_matrix::Value{ parameters.matrixForTile(clipID.first) },
508 },
509 paintAttributeData,
510 properties,
511 parameters.state.getZoom()
512 ),
513 program.computeAllAttributeBindings(
514 parameters.staticData.tileVertexBuffer,
515 paintAttributeData,
516 properties
517 ),
518 "clipping"
519 );
520 }
521 }
522
523 #if not MBGL_USE_GLES2 and not defined(NDEBUG)
524 // Render tile clip boundaries, using stencil buffer to calculate fill color.
525 if (parameters.debugOptions & MapDebugOptions::StencilClip) {
526 parameters.context.setStencilMode(gl::StencilMode::disabled());
527 parameters.context.setDepthMode(gl::DepthMode::disabled());
528 parameters.context.setColorMode(gl::ColorMode::unblended());
529 parameters.context.program = 0;
530
531 // Reset the value in case someone else changed it, or it's dirty.
532 parameters.context.pixelTransferStencil = gl::value::PixelTransferStencil::Default;
533
534 // Read the stencil buffer
535 const auto viewport = parameters.context.viewport.getCurrentValue();
536 auto image = parameters.context.readFramebuffer<AlphaImage, gl::TextureFormat::Stencil>(viewport.size, false);
537
538 // Scale the Stencil buffer to cover the entire color space.
539 auto it = image.data.get();
540 auto end = it + viewport.size.width * viewport.size.height;
541 const auto factor = 255.0f / *std::max_element(it, end);
542 for (; it != end; ++it) {
543 *it *= factor;
544 }
545
546 parameters.context.pixelZoom = { 1, 1 };
547 parameters.context.rasterPos = { -1, -1, 0, 1 };
548 parameters.context.drawPixels(image);
549
550 return;
551 }
552 #endif
553
554 // Actually render the layers
555
556 parameters.depthRangeSize = 1 - (order.size() + 2) * parameters.numSublayers * parameters.depthEpsilon;
557
558 // - OPAQUE PASS -------------------------------------------------------------------------------
559 // Render everything top-to-bottom by using reverse iterators. Render opaque objects first.
560 {
561 parameters.pass = RenderPass::Opaque;
562 MBGL_DEBUG_GROUP(parameters.context, "opaque");
563
564 uint32_t i = 0;
565 for (auto it = order.rbegin(); it != order.rend(); ++it, ++i) {
566 parameters.currentLayer = i;
567 if (it->layer.hasRenderPass(parameters.pass)) {
568 MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
569 it->layer.render(parameters, it->source);
570 }
571 }
572 }
573
574 // - TRANSLUCENT PASS --------------------------------------------------------------------------
575 // Make a second pass, rendering translucent objects. This time, we render bottom-to-top.
576 {
577 parameters.pass = RenderPass::Translucent;
578 MBGL_DEBUG_GROUP(parameters.context, "translucent");
579
580 uint32_t i = static_cast<uint32_t>(order.size()) - 1;
581 for (auto it = order.begin(); it != order.end(); ++it, --i) {
582 parameters.currentLayer = i;
583 if (it->layer.hasRenderPass(parameters.pass)) {
584 MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
585 it->layer.render(parameters, it->source);
586 }
587 }
588 }
589
590 // - DEBUG PASS --------------------------------------------------------------------------------
591 // Renders debug overlays.
592 {
593 MBGL_DEBUG_GROUP(parameters.context, "debug");
594
595 // Finalize the rendering, e.g. by calling debug render calls per tile.
596 // This guarantees that we have at least one function per tile called.
597 // When only rendering layers via the stylesheet, it's possible that we don't
598 // ever visit a tile during rendering.
599 for (const auto& entry : renderSources) {
600 if (entry.second->isEnabled()) {
601 entry.second->finishRender(parameters);
602 }
603 }
604 }
605
606 #if not MBGL_USE_GLES2 and not defined(NDEBUG)
607 // Render the depth buffer.
608 if (parameters.debugOptions & MapDebugOptions::DepthBuffer) {
609 parameters.context.setStencilMode(gl::StencilMode::disabled());
610 parameters.context.setDepthMode(gl::DepthMode::disabled());
611 parameters.context.setColorMode(gl::ColorMode::unblended());
612 parameters.context.program = 0;
613
614 // Scales the values in the depth buffer so that they cover the entire grayscale range. This
615 // makes it easier to spot tiny differences.
616 const float base = 1.0f / (1.0f - parameters.depthRangeSize);
617 parameters.context.pixelTransferDepth = { base, 1.0f - base };
618
619 // Read the stencil buffer
620 auto viewport = parameters.context.viewport.getCurrentValue();
621 auto image = parameters.context.readFramebuffer<AlphaImage, gl::TextureFormat::Depth>(viewport.size, false);
622
623 parameters.context.pixelZoom = { 1, 1 };
624 parameters.context.rasterPos = { -1, -1, 0, 1 };
625 parameters.context.drawPixels(image);
626 }
627 #endif
628
629 // TODO: Find a better way to unbind VAOs after we're done with them without introducing
630 // unnecessary bind(0)/bind(N) sequences.
631 {
632 MBGL_DEBUG_GROUP(parameters.context, "cleanup");
633
634 parameters.context.activeTextureUnit = 1;
635 parameters.context.texture[1] = 0;
636 parameters.context.activeTextureUnit = 0;
637 parameters.context.texture[0] = 0;
638
639 parameters.context.bindVertexArray = 0;
640 }
641
642 observer->onDidFinishRenderingFrame(
643 loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
644 updateParameters.mode == MapMode::Continuous && hasTransitions(parameters.timePoint)
645 );
646
647 if (!loaded) {
648 renderState = RenderState::Partial;
649 } else if (renderState != RenderState::Fully) {
650 renderState = RenderState::Fully;
651 observer->onDidFinishRenderingMap();
652 }
653
654 // Cleanup only after signaling completion
655 parameters.context.performCleanup();
656 }
657
queryRenderedFeatures(const ScreenLineString & geometry,const RenderedQueryOptions & options) const658 std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const {
659 std::vector<const RenderLayer*> layers;
660 if (options.layerIDs) {
661 for (const auto& layerID : *options.layerIDs) {
662 if (const RenderLayer* layer = getRenderLayer(layerID)) {
663 layers.emplace_back(layer);
664 }
665 }
666 } else {
667 for (const auto& entry : renderLayers) {
668 layers.emplace_back(entry.second.get());
669 }
670 }
671
672 return queryRenderedFeatures(geometry, options, layers);
673 }
674
queryRenderedSymbols(std::unordered_map<std::string,std::vector<Feature>> & resultsByLayer,const ScreenLineString & geometry,const std::vector<const RenderLayer * > & layers,const RenderedQueryOptions & options) const675 void Renderer::Impl::queryRenderedSymbols(std::unordered_map<std::string, std::vector<Feature>>& resultsByLayer,
676 const ScreenLineString& geometry,
677 const std::vector<const RenderLayer*>& layers,
678 const RenderedQueryOptions& options) const {
679
680 auto renderedSymbols = placement->getCollisionIndex().queryRenderedSymbols(geometry);
681 std::vector<std::reference_wrapper<const RetainedQueryData>> bucketQueryData;
682 for (auto entry : renderedSymbols) {
683 bucketQueryData.push_back(placement->getQueryData(entry.first));
684 }
685 // Although symbol query is global, symbol results are only sortable within a bucket
686 // For a predictable global sort order, we sort the buckets based on their corresponding tile position
687 std::sort(bucketQueryData.begin(), bucketQueryData.end(), [](const RetainedQueryData& a, const RetainedQueryData& b) {
688 return
689 std::tie(a.tileID.canonical.z, a.tileID.canonical.y, a.tileID.wrap, a.tileID.canonical.x) <
690 std::tie(b.tileID.canonical.z, b.tileID.canonical.y, b.tileID.wrap, b.tileID.canonical.x);
691 });
692
693 for (auto wrappedQueryData : bucketQueryData) {
694 auto& queryData = wrappedQueryData.get();
695 auto bucketSymbols = queryData.featureIndex->lookupSymbolFeatures(renderedSymbols[queryData.bucketInstanceId],
696 options,
697 layers,
698 queryData.tileID,
699 queryData.featureSortOrder);
700
701 for (auto layer : bucketSymbols) {
702 auto& resultFeatures = resultsByLayer[layer.first];
703 std::move(layer.second.begin(), layer.second.end(), std::inserter(resultFeatures, resultFeatures.end()));
704 }
705 }
706 }
707
queryRenderedFeatures(const ScreenLineString & geometry,const RenderedQueryOptions & options,const std::vector<const RenderLayer * > & layers) const708 std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::vector<const RenderLayer*>& layers) const {
709 std::unordered_set<std::string> sourceIDs;
710 for (const RenderLayer* layer : layers) {
711 sourceIDs.emplace(layer->baseImpl->source);
712 }
713
714 mat4 projMatrix;
715 transformState.getProjMatrix(projMatrix);
716
717 std::unordered_map<std::string, std::vector<Feature>> resultsByLayer;
718 for (const auto& sourceID : sourceIDs) {
719 if (RenderSource* renderSource = getRenderSource(sourceID)) {
720 auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
721 std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
722 }
723 }
724
725 queryRenderedSymbols(resultsByLayer, geometry, layers, options);
726
727 std::vector<Feature> result;
728
729 if (resultsByLayer.empty()) {
730 return result;
731 }
732
733 // Combine all results based on the style layer order.
734 for (const auto& layerImpl : *layerImpls) {
735 const RenderLayer* layer = getRenderLayer(layerImpl->id);
736 if (!layer->needsRendering(zoomHistory.lastZoom)) {
737 continue;
738 }
739 auto it = resultsByLayer.find(layer->baseImpl->id);
740 if (it != resultsByLayer.end()) {
741 std::move(it->second.begin(), it->second.end(), std::back_inserter(result));
742 }
743 }
744
745 return result;
746 }
747
queryShapeAnnotations(const ScreenLineString & geometry) const748 std::vector<Feature> Renderer::Impl::queryShapeAnnotations(const ScreenLineString& geometry) const {
749 std::vector<const RenderLayer*> shapeAnnotationLayers;
750 RenderedQueryOptions options;
751 for (const auto& layerImpl : *layerImpls) {
752 if (std::mismatch(layerImpl->id.begin(), layerImpl->id.end(),
753 AnnotationManager::ShapeLayerID.begin(), AnnotationManager::ShapeLayerID.end()).second == AnnotationManager::ShapeLayerID.end()) {
754 if (const RenderLayer* layer = getRenderLayer(layerImpl->id)) {
755 shapeAnnotationLayers.emplace_back(layer);
756 }
757 }
758 }
759
760 return queryRenderedFeatures(geometry, options, shapeAnnotationLayers);
761 }
762
querySourceFeatures(const std::string & sourceID,const SourceQueryOptions & options) const763 std::vector<Feature> Renderer::Impl::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
764 const RenderSource* source = getRenderSource(sourceID);
765 if (!source) return {};
766
767 return source->querySourceFeatures(options);
768 }
769
reduceMemoryUse()770 void Renderer::Impl::reduceMemoryUse() {
771 assert(BackendScope::exists());
772 for (const auto& entry : renderSources) {
773 entry.second->reduceMemoryUse();
774 }
775 backend.getContext().performCleanup();
776 observer->onInvalidate();
777 }
778
dumDebugLogs()779 void Renderer::Impl::dumDebugLogs() {
780 for (const auto& entry : renderSources) {
781 entry.second->dumpDebugLogs();
782 }
783
784 imageManager->dumpDebugLogs();
785 }
786
getRenderLayer(const std::string & id)787 RenderLayer* Renderer::Impl::getRenderLayer(const std::string& id) {
788 auto it = renderLayers.find(id);
789 return it != renderLayers.end() ? it->second.get() : nullptr;
790 }
791
getRenderLayer(const std::string & id) const792 const RenderLayer* Renderer::Impl::getRenderLayer(const std::string& id) const {
793 auto it = renderLayers.find(id);
794 return it != renderLayers.end() ? it->second.get() : nullptr;
795 }
796
getRenderSource(const std::string & id) const797 RenderSource* Renderer::Impl::getRenderSource(const std::string& id) const {
798 auto it = renderSources.find(id);
799 return it != renderSources.end() ? it->second.get() : nullptr;
800 }
801
hasTransitions(TimePoint timePoint) const802 bool Renderer::Impl::hasTransitions(TimePoint timePoint) const {
803 if (renderLight.hasTransition()) {
804 return true;
805 }
806
807 for (const auto& entry : renderLayers) {
808 if (entry.second->hasTransition()) {
809 return true;
810 }
811 }
812
813 if (placement->hasTransitions(timePoint)) {
814 return true;
815 }
816
817 if (fadingTiles) {
818 return true;
819 }
820
821 return false;
822 }
823
updateFadingTiles()824 void Renderer::Impl::updateFadingTiles() {
825 fadingTiles = false;
826 for (auto& source : renderSources) {
827 for (auto& renderTile : source.second->getRenderTiles()) {
828 Tile& tile = renderTile.get().tile;
829 if (tile.holdForFade()) {
830 fadingTiles = true;
831 tile.performedFadePlacement();
832 }
833 }
834 }
835 }
836
isLoaded() const837 bool Renderer::Impl::isLoaded() const {
838 for (const auto& entry: renderSources) {
839 if (!entry.second->isLoaded()) {
840 return false;
841 }
842 }
843
844 if (!imageManager->isLoaded()) {
845 return false;
846 }
847
848 return true;
849 }
850
onGlyphsError(const FontStack & fontStack,const GlyphRange & glyphRange,std::exception_ptr error)851 void Renderer::Impl::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
852 Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s",
853 glyphRange.first, glyphRange.second, fontStackToString(fontStack).c_str(), util::toString(error).c_str());
854 observer->onResourceError(error);
855 }
856
onTileError(RenderSource & source,const OverscaledTileID & tileID,std::exception_ptr error)857 void Renderer::Impl::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) {
858 Log::Error(Event::Style, "Failed to load tile %s for source %s: %s",
859 util::toString(tileID).c_str(), source.baseImpl->id.c_str(), util::toString(error).c_str());
860 observer->onResourceError(error);
861 }
862
onTileChanged(RenderSource &,const OverscaledTileID &)863 void Renderer::Impl::onTileChanged(RenderSource&, const OverscaledTileID&) {
864 observer->onInvalidate();
865 }
866
867 } // namespace mbgl
868