Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't load tiles that will be shown in a very small number of frames while animating #5482

Open
lbud opened this issue Oct 18, 2017 · 5 comments

Comments

@lbud
Copy link
Contributor

lbud commented Oct 18, 2017

Motivation

When animating the map, it's possible to create a scenario where tiles are repeatedly requested but never cached:

For example, when repeatedly animating back and forth between z7.5 and z8.5, all necessary z7 tiles for the resting z7.5 state will be retained, and all necessary z8 tiles for the resting z8.5 state will be retained, but there may be (likely, but depends on exact viewport dimensions) rows and/or columns of z8 tiles that will be needed only in a few frames in the middle of the animation (they'll be outside of the viewport when the map is a bit further zoomed in to 8.5). We request those tiles during the animation, but then when the SourceCache goes to remove it, it's not added to the cache because its state is still 'loading', so it fails a hasData() check. The tile is aborted, never finishes loading and is never cached, so it'll be repeatedly requested when zooming back and forth between these fractional zooms. (A similar case may happen in any animation — flyTo, etc — or with rapid pan/zoom scrubbing.)

Design Alternatives

  • Make tile loading aware of ongoing animations, calculate the duration that a new tile will be visible based on the animation, and decide on some heuristic that determines that n frames isn't worth loading a tile (especially if we have another tile available that we could overzoom perhaps).

  • Circumstantially loosen rules about tile aborting. Maybe tiles in certain situations (tiles requested during programmatic animations? Raster tiles, since they don't require bucket parsing? Any tiles, when a map/source allowTilesToFinishProcessing param is set?) could be allowed to finish downloading and immediately moved to the cache.

  • Provide developers with a way to preload tiles for an animation (Preloading tiles for camera animation #2470).

  • Do nothing.

Design

I don't have a strong conviction on what's the right/best answer here, but option 1 seems reasonable and practical. It's possible we may need to make this a configurable heuristic.

cc @mapbox/gl-core

@kkaefer
Copy link
Contributor

kkaefer commented Oct 19, 2017

As @jfirebaugh pointed out, option 1 requires that animations are driven by Mapbox GL internally, rather than being driven by a the SDK (e.g. as part of platform-provided animations, or int he navigation SDK).

@ansis
Copy link
Contributor

ansis commented Oct 19, 2017

Another design alternative:

Use some kind of heuristic approach based on momentum to predict which tiles won't be visible for long enough to load fully. It could then delay them by some amount of time so that they can be aborted cleanly.

Pros: does not require advance knowledge about the animation, and it might also work for regular user zooming and panning
Cons: not exact, more complicated, makes tile loading slightly slower in some cases

Option 1 sounds better I think, but ^ might be worth considering.


If you know which tiles not to to load you probably know which tiles you will want to load and can start doing this ahead of time. Even if you don't fully preload an animation you can preload a future part of the animation while animating.

@mourner
Copy link
Member

mourner commented Jul 27, 2018

We could borrow a relatively simple solution that partially addresses this issue from OpenLayers. Capturing discussion in #6643:

From #7008:

I've ported the example to OpenLayers, with a similar animation (the easing is different).
In my opinion OL is super smooth even with developer tools open. FPS meter shows constant 60 FPS with one or two occasional frames at 30 FPS, or maybe 20 FPS.

I've looked into how OpenLayers handles raster tile loading, and I believe the reason why their equivalent is fast is that they use a TileQueue data structure that makes sure there are never more than 16 tiles loading in parallel or requested at once in one frame. This makes it avoid requesting short-lived tiles that e.g. get requested on zoom in near the borders of the map and then immediately go off the view when zooming further during an animation. This might be a possible solution to this feature request #5482, and we should definitely explore a similar approach.

@ChrisLoer
Copy link
Contributor

This is a slightly different variant of the problem, but now that we have symbol cross-fading, we'll keep rendering tiles with symbols for at least 300ms after the last time they were an ideal tile. This means that in cached/fast-network situations where we're able to load tiles very quickly during an animation, we can end up with a lot of overlapping tiles rendering simultaneously. With that much movement going on in the animation, the cross-fade effect itself is probably perceptually negligible and we'd rather avoid all the extra draw calls. We might be able to address this with some simple heuristics like "don't hold for cross fade if you're more than 2 (1?) zoom levels away from ideal zoom", as suggested in mapbox/mapbox-gl-native#12356.

@allthesignals
Copy link
Contributor

After some research, I think this issue describes my problem - although it is less about caching or more about requesting tiles during animations.

For example, we use flyTo to transition across different views. When those views represent places that are significantly far apart, the flying animations will kick of dozens of requests for tiles, leading to around 2mb of tile data. I'm interested in a way to control whether new tiles are requested during this transition or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants