Skip to content

Support debounceTime in MosaicLayer (flat tile model breaks deck.gl's debounced scheduler) #562

@kylebarron

Description

@kylebarron

Summary

MosaicLayer does not support a non-zero debounceTime. Setting one causes source tiles to never load. The prop is therefore intentionally not exposed on MosaicLayer (removed in #557). It continues to work on COGLayer / MultiCOGLayer, which are normal hierarchical RasterTileLayer tile pyramids.

Motivation

For a mosaic of many COGs, panning sweeps the viewport across lots of sources and opens GeoTIFFs for every intermediate viewport. A debounce would let us open sources only for where the user stops, instead of churning through everything passed over. deck.gl's TileLayer exposes debounceTime for exactly this, but it's incompatible with MosaicLayer's tile model (see below).

What we found

MosaicTileset2D uses a flat, zoomless tile model: every source is a tile at zoom 0, and getParentIndex returns the tile itself, so there is no parent/child hierarchy.

  • A single static update() actually loads fine with a non-zero debounceTime — verified by tracing: _getTile enqueues the request, updateTileStates() sets isSelected = true, and when the debounce timer fires the scheduler sees priority isSelected ? 1 : -1 === 1 and grants it.
  • The failure appears under repeated update() calls (viewport churn from panning, map settle, and/or the interleaved overlay's per-frame repaints). deck.gl's RequestScheduler re-evaluates isSelected ? 1 : -1 at issue time and cancels any tile not selected at that instant; a cancelled tile's needsReload becomes true, so it's re-scheduleRequested as a new handle, which resets the debounce timer (clearTimeout + setTimeout). The net effect is that the debounce window never closes on a stable selected set, so requests are never issued.
  • The flat model also removes deck.gl's normal cushion: with no ancestor/child tree, unloaded tiles never get isVisible: true and there are no lower-res placeholders to show while debouncing.

Relevant source:

  • Tile2DHeader._loadData priority tile => tile.isSelected ? 1 : -1 (no token ⇒ cancelled)
  • RequestScheduler._issueNewRequests (clearTimeout/setTimeout(debounceTime) on every new enqueue)
  • Tileset2D._getTile re-loads tiles whose needsReload (incl. _isCancelled) is true
  • MosaicTileset2D (getTileZoom → 0, getParentIndex → self)

Caveat: the single-update path was traced from source; the exact dominant trigger under the live render loop (initial-settle churn vs. the cancel→reschedule loop) was not instrumented.

Possible directions

  • Implement debouncing at the MosaicLayer getSource level instead of forwarding to deck.gl's scheduler.
  • Give MosaicTileset2D a stable selection / a non-degenerate tree so deck.gl's debounced scheduler behaves.
  • Upstream: a deck.gl scheduler mode that doesn't reset the debounce timer for already-queued handles, or doesn't cancel on transient deselection.

Context: split out of #557.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions