You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
deck.gl has accumulated a long stream of canvas, device, resize, attach, detach, async initialization, and teardown fixes. We should address the underlying ownership and lifecycle contracts in luma.gl instead of stacking integration-specific fixes in deck.gl.
React StrictMode and rapid create/finalize/create cycles can complete device creation after the original owner was finalized. _reuseDevices avoided crashes but previously prevented real teardown.
Reference-counted reusable devices, plus follow-up cancellation or late-result disposal for async creation.
Replace _reuseDevices no-op teardown with reference-counted final teardown.
Add terminal Device.detach() semantics for exclusively owned devices.
Phase 2 — Native WebGL event-listener lifecycle
Retain and remove webglcontextlost and webglcontextrestored listeners during final destroy() and terminal detach().
Preserve listeners during intermediate _reuseDevices releases.
Ensure later attach/recreate cycles install only one active listener pair.
Add browser tests for destroy, detach, reuse, and reattach.
Phase 3 — Async creation and finalize safety
Define cancellation or late-result disposal for async device creation.
Prevent devices that finish after owner finalization from starting observers, inserting canvases, or remaining attached.
Cover React StrictMode create/finalize/create timing and rapid overlay replacement.
Coordinate deck.gl follow-up so internally acquired devices are always released.
Phase 4 — Attached and externally owned canvas sizing
Define resize contracts for standalone, attached/shared-GL, overlaid, and external-framebuffer contexts.
Ensure attached contexts do not mutate externally owned canvases unless explicitly requested.
Avoid parallel resize paths fighting over autoResize, useDevicePixels, DPR, and drawing-buffer dimensions.
Provide enough CanvasContext state/hooks for deck.gl viewport sizing, picking, and redraw invalidation.
Cover DPR changes, fractional zoom, fullscreen transitions, and basemap overlays.
Phase 5 — Documentation and downstream adoption
Document wrapper, DOM canvas, backend-handle, and resize ownership separately.
Document destroy(), early wrapper destruction, _reuseDevices, attach(), and terminal detach().
Clarify that destroyed WebGPU wrappers are not reusable, while the canvas/native context can be wrapped again after unconfiguration.
Update deck.gl to call device.destroy() for internally acquired devices instead of directly destroying _canvasContext.
Preserve caller ownership for externally supplied devices, GL contexts, canvases, and framebuffers.
Non-goals
Device teardown does not remove caller-supplied DOM canvases.
Device ownership does not automatically include every GPU resource created by user code.
luma cannot clean up objects whose references are dropped without calling destroy().
Rendering/FBO invalidation bugs remain separate unless they expose a missing lifecycle or sizing contract.
Success criteria
Final device release leaves no active CanvasContext observers, timers, DPR listeners, position polling, native context event listeners, or stale context metadata.
_reuseDevices acquisitions require matching releases; intermediate releases preserve usability and final release performs real teardown.
detach() returns a reusable backend handle without leaving luma-owned wrappers or listeners behind.
Late async initialization cannot resurrect a finalized owner.
External canvases are not removed or unexpectedly resized.
deck.gl can rely on documented luma lifecycle and sizing contracts instead of per-overlay cleanup and resize patches.
Why
deck.gl has accumulated a long stream of canvas, device, resize, attach, detach, async initialization, and teardown fixes. We should address the underlying ownership and lifecycle contracts in luma.gl instead of stacking integration-specific fixes in deck.gl.
One round of bigger root-level work is in #2742.
Ownership model
CanvasContext/PresentationContextwrapperDevicedestroy()releases owned handles;detach()removes luma ownership and returns the reusable backend handle.Evidence from deck.gl
_reuseDevicesavoided crashes but previously prevented real teardown.attach()/detach()lifecycle, native event-listener teardown, and explicit external-canvas ownership rules.Phase 1 — Device-owned canvas wrappers
Device._reuseDevicesno-op teardown with reference-counted final teardown.Device.detach()semantics for exclusively owned devices.Phase 2 — Native WebGL event-listener lifecycle
webglcontextlostandwebglcontextrestoredlisteners during finaldestroy()and terminaldetach()._reuseDevicesreleases.Phase 3 — Async creation and finalize safety
Phase 4 — Attached and externally owned canvas sizing
autoResize,useDevicePixels, DPR, and drawing-buffer dimensions.Phase 5 — Documentation and downstream adoption
destroy(), early wrapper destruction,_reuseDevices,attach(), and terminaldetach().device.destroy()for internally acquired devices instead of directly destroying_canvasContext.Non-goals
destroy().Success criteria
_reuseDevicesacquisitions require matching releases; intermediate releases preserve usability and final release performs real teardown.detach()returns a reusable backend handle without leaving luma-owned wrappers or listeners behind.