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

fix recursive dem tiles loading for 404s #11276

Merged
merged 14 commits into from
Dec 21, 2021
Merged

fix recursive dem tiles loading for 404s #11276

merged 14 commits into from
Dec 21, 2021

Conversation

stepankuzmin
Copy link
Contributor

@stepankuzmin stepankuzmin commented Nov 12, 2021

Launch Checklist

This PR fixes recursive dem tiles loading according to #11161

  • briefly describe the changes in this PR
  • write tests for all new functionality
  • manually test the debug page
  • apply changelog label ('bug', 'feature', 'docs', etc) or use the label 'skip changelog'
  • add an entry inside this element for inclusion in the mapbox-gl-js changelog: <changelog>fix recursive dem tiles loading for 404s</changelog>

Before

before-dem-fix.mov

After

after-dem-fix.mov

@mourner mourner linked an issue Nov 12, 2021 that may be closed by this pull request
@stepankuzmin stepankuzmin changed the title fix recursive dem tiles loading for 404s [WIP] fix recursive dem tiles loading for 404s Nov 15, 2021
@stepankuzmin
Copy link
Contributor Author

Tests are failing because sourceCache doesn't contain some tiles that are available at the terrain lookup path in _findTileCoveringTileID see https://github.com/mapbox/mapbox-gl-js/blob/main/src/terrain/terrain.js#L1339

also, the terrain is wiggling

terrain-wiggling.mov

@ansis
Copy link
Contributor

ansis commented Nov 17, 2021

Other than failing tests, this looks good.

Is there anything we can do further to make this less brittle? If we wanted to refactor and remove the updateForTerrain argument, what would that look like? Or maybe we could just make the argument not optional.

Copy link
Contributor

@astojilj astojilj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is useful to evaluate what happens (what tile requests are made) when displaying sea view. In such case, 404s are used for tiles away from land.

@@ -241,14 +241,14 @@ class SourceCache extends Evented {
tile.state = 'errored';
if ((err: any).status !== 404) this._source.fire(new ErrorEvent(err, {tile}));
// continue to try loading parent/children tiles if a tile doesn't exist (404)
else this.update(this.transform);
else this.update(this.transform, undefined, this._source.type === 'raster-dem');
Copy link
Contributor

@astojilj astojilj Nov 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is good to evaluate what happens when when raster dem source is not used for terrain, but only for hillshade. userForTerrain property gets evaluated to true here.

Otherwise, when used for terrain, we need to cache tile size for this source supplied (it is scaled up in code below) and if in consecutive update here we end up requesting tile cover with different tile size. This is apparently the issue that existed before but now with sparse dem tile set the behavior is different.

this.sourceCache.update(transform, demScale * proxyTileSize, true);

@stepankuzmin
Copy link
Contributor Author

The test is initiating tiles requests on the 14th zoom level and blocks tiles requests for zoom levels below 12 at the same time.

loadTile (tile, callback) {
if (tile.tileID.canonical.z > 12) {
setTimeout(() => callback({status: 404}), 0);
} else {
tile.state = 'loaded';
callback(null);
}
}

Without the fix, sourceCache.getRenderableIds() doesn't contain any tiles for raster-dem sources that is used for terrain and sourceCache.getIds() only contains tiles for the requested zoom level.

t.deepEqual(sourceCache.getRenderableIds(), []);

t.deepEqual(sourceCache.getIds(), [
    new OverscaledTileID(14, 0, 14, 8192, 8192).key,
    new OverscaledTileID(14, 0, 14, 8191, 8192).key,
    new OverscaledTileID(14, 0, 14, 8192, 8191).key,
    new OverscaledTileID(14, 0, 14, 8191, 8191).key,
]);

After the fix, raster-dem sources used for terrain behave the same way as the other sources, i.e., recursively load parent tiles if current tiles are not found.

t.deepEqual(sourceCache.getRenderableIds(), [
    new OverscaledTileID(12, 0, 12, 2048, 2048).key,
    new OverscaledTileID(12, 0, 12, 2047, 2048).key,
    new OverscaledTileID(12, 0, 12, 2048, 2047).key,
    new OverscaledTileID(12, 0, 12, 2047, 2047).key,
]);

t.deepEqual(sourceCache.getIds(), [
    new OverscaledTileID(12, 0, 12, 2048, 2048).key,
    new OverscaledTileID(12, 0, 12, 2047, 2048).key,
    new OverscaledTileID(12, 0, 12, 2048, 2047).key,
    new OverscaledTileID(12, 0, 12, 2047, 2047).key,
    new OverscaledTileID(13, 0, 13, 4096, 4096).key,
    new OverscaledTileID(13, 0, 13, 4095, 4096).key,
    new OverscaledTileID(13, 0, 13, 4096, 4095).key,
    new OverscaledTileID(13, 0, 13, 4095, 4095).key,
    new OverscaledTileID(14, 0, 14, 8192, 8192).key,
    new OverscaledTileID(14, 0, 14, 8191, 8192).key,
    new OverscaledTileID(14, 0, 14, 8192, 8191).key,
    new OverscaledTileID(14, 0, 14, 8191, 8191).key,
]);

/cc @ansis @astojilj

@stepankuzmin
Copy link
Contributor Author

stepankuzmin commented Nov 22, 2021

There are some failing tests. One is render-tests/free-camera/terrain; it times out after 5000ms on CI but passes on with watch-render. UPDATE: seems that this was a flaky test

The other one is render-tests/debug/terrain/camera-under-terrain. It fails because of the transparent background (sky?) on the first render.

Screenshot 2021-11-22 at 15 25 06

Here is the video of the camera-under-terrain/style.json before and after the fix was applied. I'm not sure if it's significant.

Before

cut-before.mov

After

cut-after.mov

I've updated the expected.png for this test


eventedParent.on('data', (e) => {
if (e.dataType === 'source' && e.sourceDataType === 'metadata') {
sourceCache.update(transform, undefined, sourceCache.usedForTerrain);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined for tileSize is a bit problematic as it doesn't verify real case:

// As a result of update, we get new set of tiles: reset lookup cache.
this._findCoveringTileCache[this.sourceCache.id] = {};

I'd suggest to use transform.zoom = 16, tileSize of 4 * 512 and DEM source maxZoom of 10.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created a separate test for the terrain

test('terrain recursively loads parent tiles on 404', (t) => {
t.plan(2);
const style = createStyle();
const map = createMap(t, {style, center: [0, 0], zoom: 16});
map.once('style.load', () => {
map.addSource('mapbox-dem', {
'type': 'raster-dem',
'tiles': ['http://example.com/{z}/{x}/{y}.png'],
'tileSize': TILE_SIZE,
'maxzoom': 14
});
const cache = map.style._getSourceCache('mapbox-dem');
cache.used = cache._sourceLoaded = true;
cache._loadTile = (tile, callback) => {
if (tile.tileID.canonical.z > 10) {
setTimeout(() => callback({status: 404}), 0);
} else {
tile.state = 'loaded';
callback(null);
}
};
map.setTerrain({'source': 'mapbox-dem'});
map.once('idle', () => {
t.deepEqual(cache.getRenderableIds(), [
new OverscaledTileID(10, 0, 10, 512, 512).key,
new OverscaledTileID(10, 0, 10, 511, 512).key,
new OverscaledTileID(10, 0, 10, 512, 511).key,
new OverscaledTileID(10, 0, 10, 511, 511).key,
], 'contains first renderable tiles');
t.deepEqual(cache.getIds(), [
new OverscaledTileID(10, 0, 10, 512, 512).key,
new OverscaledTileID(10, 0, 10, 511, 512).key,
new OverscaledTileID(10, 0, 10, 512, 511).key,
new OverscaledTileID(10, 0, 10, 511, 511).key,
new OverscaledTileID(11, 0, 11, 1024, 1024).key,
new OverscaledTileID(11, 0, 11, 1023, 1024).key,
new OverscaledTileID(11, 0, 11, 1024, 1023).key,
new OverscaledTileID(11, 0, 11, 1023, 1023).key,
new OverscaledTileID(12, 0, 12, 2048, 2048).key,
new OverscaledTileID(12, 0, 12, 2047, 2048).key,
new OverscaledTileID(12, 0, 12, 2048, 2047).key,
new OverscaledTileID(12, 0, 12, 2047, 2047).key,
new OverscaledTileID(13, 0, 13, 4096, 4096).key,
new OverscaledTileID(13, 0, 13, 4095, 4096).key,
new OverscaledTileID(13, 0, 13, 4096, 4095).key,
new OverscaledTileID(13, 0, 13, 4095, 4095).key,
new OverscaledTileID(14, 0, 14, 8192, 8192).key,
new OverscaledTileID(14, 0, 14, 8191, 8192).key,
new OverscaledTileID(14, 0, 14, 8192, 8191).key,
new OverscaledTileID(14, 0, 14, 8191, 8191).key,
], 'recursively loads parent tiles if current tiles not found');
});
});

@stepankuzmin stepankuzmin changed the title [WIP] fix recursive dem tiles loading for 404s fix recursive dem tiles loading for 404s Dec 20, 2021
src/source/source_cache.js Outdated Show resolved Hide resolved
src/terrain/terrain.js Outdated Show resolved Hide resolved
Copy link
Contributor

@karimnaaji karimnaaji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@karimnaaji karimnaaji merged commit ade9271 into main Dec 21, 2021
@karimnaaji karimnaaji deleted the raster-dem-404 branch December 21, 2021 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

recursive tile loading for 404s doesn't work for dem tiles
4 participants