Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/deck.gl-geotiff/src/mosaic-layer/mosaic-tileset-2d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ export class MosaicTileset2D<ItemT extends MosaicItem> extends Tileset2D {
this.getItems = getItems;
}

/**
* Unloads every cached item, which deck.gl's `finalize` skips until
* https://github.com/visgl/deck.gl/pull/10883 lands. An item still opening
* is unloaded once its open finishes.
*/
override finalize(): void {
const { onTileUnload } = this.opts;
for (const tile of this.tiles) {
if (tile.isLoading) {
// `data` is a promise until the load finishes
void Promise.resolve(tile.data).then(() => onTileUnload(tile));
} else {
onTileUnload(tile);
}
}
super.finalize();
}

/** The Tileset2D cache key for an item. */
override getTileId(tileIndex: TileIndex): string {
// `getTileIndices` always returns `ResolvedItem`s, so an `id` is
Expand Down
39 changes: 38 additions & 1 deletion packages/deck.gl-geotiff/tests/mosaic-layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,14 @@ function makeMosaicRenderer(viewport: WebMercatorViewport = VIEWPORT) {
layerManager.activateViewport(next);
};

return { render, wait, moveTo };
/** Remove the layer, as an app does by no longer rendering it. */
const remove = async () => {
layerManager.setLayers([]);
await settle(layerManager);
return report();
};

return { render, wait, moveTo, remove };
}

// The tests above reuse one layer instance. Apps create a new MosaicLayer on
Expand Down Expand Up @@ -455,6 +462,36 @@ describe("MosaicLayer sources", () => {
expect(errors).toEqual([]);
expect(unloaded).toEqual({ A: { of: "A" }, B: { of: "B" } });
});

it("passes every cached item's source to onSourceUnload when the layer is removed", async () => {
const { render, remove } = makeMosaicRenderer();
await render({ data: [A, B] });

const { unloaded, errors } = await remove();
expect(errors).toEqual([]);
expect(unloaded).toEqual({ A: { of: "A" }, B: { of: "B" } });
});

it("passes the source of an item still opening at removal to onSourceUnload once it arrives", async () => {
const { render, remove, wait } = makeMosaicRenderer();
let finish!: () => void;
await render({
data: [A],
// Ignores the abort, as a source cache shared between loads can
getSource: (item) =>
new Promise((resolve) => {
finish = () => resolve({ of: item.id });
}),
});

// A copy: the report's records keep filling in
const atRemoval = { ...(await remove()).unloaded };
finish();
const { unloaded, errors } = await wait();
expect(errors).toEqual([]);
expect(atRemoval).toEqual({});
expect(unloaded).toEqual({ A: { of: "A" } });
});
});

describe("MosaicLayer fetch priority", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ export class RasterTileset2D extends Tileset2D {
* without calling `onTileUnload`, so GPU resources that `getTileData` made
* for those tiles, like textures, would be freed only by garbage collection.
* A tile still loading is unloaded once its load finishes, since deck.gl
* keeps the data that `getTileData` returns after an abort.
* keeps the data that `getTileData` returns after an abort. Not needed once
* https://github.com/visgl/deck.gl/pull/10883 lands.
*/
override finalize(): void {
const { onTileUnload } = this.opts;
Expand Down
Loading