diff --git a/src/maps/controller.js b/src/maps/controller.js index 4d0488413..65e06b144 100644 --- a/src/maps/controller.js +++ b/src/maps/controller.js @@ -147,25 +147,16 @@ export class MapSourceController { if (!tileset) { if (!source.createTileset) throw new Error(`Missing 3D source: ${source.descriptor.id}`); - tileset = await this._cached( - this._tilesets, - source.descriptor.id, - async () => { - const value = await source.createTileset({ - signal: this._abort.signal, - }); - if (this._destroyed) { - this._dispose(value); - return value; - } - value.show = false; - this.viewer.scene.primitives.add(value); - this._ownedTilesets.add(value); - return value; - }, + tileset = await this._cached(this._tilesets, source.descriptor.id, () => + source.createTileset({ signal: this._abort.signal }), ); } if (gen !== this._switchGen) return; + if (!source.tileset && !this._ownedTilesets.has(tileset)) { + tileset.show = false; + this.viewer.scene.primitives.add(tileset); + this._ownedTilesets.add(tileset); + } this._removeImageryLayer(); this._credits.show(source.credit || null); this._showTileset(tileset); @@ -325,6 +316,11 @@ export class MapSourceController { this.viewer.scene.primitives.remove(tileset); this._dispose(tileset); } + for (const promise of this._tilesets.values()) + void Promise.resolve(promise).then( + (value) => this._dispose(value), + () => {}, + ); this._imageryProviders.clear(); this._terrainProviders.clear(); this._tilesets.clear(); diff --git a/src/maps/controller.test.mjs b/src/maps/controller.test.mjs index b7a721341..c80a9c769 100644 --- a/src/maps/controller.test.mjs +++ b/src/maps/controller.test.mjs @@ -298,3 +298,54 @@ test('invalid source graphs fail before constructing or caching a provider', () assert.throws(() => fixture({ sources: [a, a] }), /unique/); assert.throws(() => fixture({ sources: [a] }), /Unknown map fallback/); }); + +for (const reactivate of [false, true]) { + test(`a superseded 3D load stays outside the scene and is released (reactivate: ${reactivate})`, async () => { + let resolve, + destroyed = 0, + reads = 0; + const tileset = { + show: true, + isDestroyed: () => destroyed > 0, + destroy() { + destroyed++; + }, + }; + const supplied = { show: true }; + const env = fixture({ + defaultId: 'slow', + sources: [ + { + descriptor: { id: 'slow' }, + createTileset: () => { + reads++; + return new Promise((done) => { + resolve = done; + }); + }, + }, + { descriptor: { id: 'supplied' }, tileset: supplied }, + ], + }); + const loading = env.controller.setStack('slow'); + await settle(); + await env.controller.setStack('supplied'); + resolve(tileset); + await loading; + assert.equal(env.primitives.length, 0); + assert.equal(supplied.show, true); + assert.equal(env.controller.getActiveId(), 'supplied'); + if (reactivate) { + await env.controller.setStack('slow'); + await env.controller.setStack('slow'); + assert.deepEqual(env.primitives, [tileset]); + assert.equal(reads, 1); + assert.equal(tileset.show, true); + assert.equal(supplied.show, false); + } + env.controller.destroy(); + await settle(); + assert.equal(env.primitives.length, 0); + assert.equal(destroyed, 1); + }); +}