chore(core) Adopt luma CanvasContext#10228
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f0c4b8b8a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| this._updateCanvasSize(); | ||
| if (this._pollCanvasContextSize) { |
There was a problem hiding this comment.
Is this primarily intended to be a performance optimization to remove unnecessary syntonization when the device is internal and deck owns the onResize wiring?
There was a problem hiding this comment.
This separate path between internal and externally created devices is the main remaining wart.
My current understanding is that we need some changes in luma to get around this.
I updated the implementation to be more CanvasContext centric and added a second infographic to the PR description to illustrate the two flows.
| this._needsRedraw = 'Canvas resized'; | ||
| // Attached contexts still emit resize through luma's CanvasContext. | ||
| // Deck only mirrors that state into viewport dimensions and redraw flags. | ||
| this._onCanvasContextResize(canvasContext); |
There was a problem hiding this comment.
The removal of setDrawingBufferSize here causes a resize regression in interleaved modes (MapLibre, Mapbox, etc).
webgl2Adapter.attach() sets autoResize: false on the canvas context (webgl-adapter.ts:73), which means luma's _updateDrawingBufferSize() in canvas-surface.ts skips updating the drawing buffer when the ResizeObserver fires. The CSS size tracking (cssWidth/cssHeight) updates correctly, but luma's internal drawingBufferWidth/drawingBufferHeight never sync to the new canvas dimensions.
So while CanvasContext is indeed the authority for observing the resize, it doesn't act on it for attached contexts - someone still has to call setDrawingBufferSize. On master that was Deck.. this PR removes that call assuming luma handles it, but luma explicitly doesn't for autoResize: false.
Possible paths forward:
- Restore the
setDrawingBufferSizecall here (what master does, see fix(core): restore drawing buffer sync for attached GL contexts on resize #10281) - Change luma's
attach()to not disableautoResize, or add a separate flag that skips only the canvas element resize but still syncs the drawing buffer tracking - Add an "installable resize listener" on CanvasContext (as you mentioned in the "Future Opportunity" section) that handles this automatically
There was a problem hiding this comment.
@chrisgervang I tried to address this concern can you take another look?
There was a problem hiding this comment.
Looks good! Just did a full side-by-side comparison between this PR and the behavior on master, and they behave identically.
The only remaining issue I found was a "flashing" bug across environments in interleaved mode, but I observed this before and after this change, so it's not a regression.. something to follow up on separately.
flashing.short.mov
There was a problem hiding this comment.
I recall doing a fix for flashing during resize in the main canvas, might be worth reviewing:
This reverts commit b13922f.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fb12200. Configure here.
| this.widgetManager.addDefault(new TooltipWidget()); | ||
|
|
||
| this.setProps(this.props); | ||
| this.setProps({}); |
There was a problem hiding this comment.
useDevicePixels never forwarded for attached GL contexts
Medium Severity
For the props.gl attach path (Mapbox/MapLibre interleaved mode), useDevicePixels is never forwarded to the luma canvas context. In the constructor, _canvasContext is still null when setProps(initialProps) runs because the device is a promise. Later, _setDevice sets _canvasContext but then calls setProps({}) — and since {}.useDevicePixels === undefined, the condition props.useDevicePixels !== undefined is false, so forwarding is skipped. Previously setProps(this.props) always had useDevicePixels defined (defaulting to true), so it was forwarded after device initialization. Users who set useDevicePixels: false or a numeric DPR override with attached GL contexts will have that preference silently ignored.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit fb12200. Configure here.
There was a problem hiding this comment.
Actually, this regression was introduced sometime during 9.3 development..
-
useDevicePixelson standalone Deck regressed in 9.3 — it works on 9.1 and 9.2 but not 9.3. This is a pre-existing regression on master, unrelated to this PR. -
useDevicePixelsin interleaved mode never worked, and that's ok (9.1, 9.2, 9.3) — because MapLibre/Mapbox owns the canvas and its drawing buffer. The correct mechanism is MapLibre'spixelRatioconstructor option, which works across all versions including Ib's branch.
So the Bugbot finding was technically accurate about the code path but mis-attributed the impact - the real issue is a 9.3 master regression on the standalone useDevicePixels, which is a separate bug
chrisgervang
left a comment
There was a problem hiding this comment.
The DPR regression should be addressed before shipping
| canvasContext.setDrawingBufferSize(width, height); | ||
|
|
||
| this._needsRedraw = 'Canvas resized'; | ||
| userOnResize?.(canvasContext, info); |
There was a problem hiding this comment.
Nit: if a user passes deviceProps.onResize, it gets spread onto the device here but is then unconditionally overwritten in _setDeviceResizeHandler (line 1082) without forwarding. The old code preserved the user callback. Probably not blocking since none of our integrations use it, but worth noting as an intentional public API change or adding a forward call back.
There was a problem hiding this comment.
I believe I added documentation for this overwrite in deck docs.
My overall assessment was that it was not really worth the extra complexity to try to handle this.
We can add it back later if needed.
| this.widgetManager.addDefault(new TooltipWidget()); | ||
|
|
||
| this.setProps(this.props); | ||
| this.setProps({}); |



Summary
Compared to
master, this PR moves deck.gl toward a single source of truth for canvas integration by treating luma.glCanvasContextas the authority for:Deck still owns viewport updates, redraw invalidation, picking orchestration, and callback wiring, but it no longer duplicates canvas sizing logic that already lives in luma.
Why
The goal is to ensure deck.gl has one canvas integration authority: luma.gl
CanvasContext.On
master, Deck still had places where it:This PR makes the contract cleaner:
CanvasContextowns resize observation, DPR tracking, drawing-buffer sizing, and CSS/device pixel conversionWhat changed vs
masterCore canvas ownership
CanvasContext-backed size reads.CanvasContextplumbing insideDeck._onCanvasContextResize(canvasContext).DeckProps.onResizebehavior, now driven by luma canvas state.CanvasContextduring render frames, without mutating user-owneddevice.props.onResize.Picking / buffer sizing
CanvasContextinto internal picking operations.canvasContext.getDrawingBufferSize().Basemap integrations
Future multi-canvas posture
canvases,canvasId,CanvasManager, per-canvas event managers, orPresentationContextrendering.Future Opportunity
The paths for external contexts is still separated. Adding installable resize listeners on luma.gl Device and CanvasContext could help here.
Files changed vs
mastermodules/core/src/lib/deck.tsmodules/core/src/lib/deck-picker.tsmodules/mapbox/src/deck-utils.tsmodules/google-maps/src/utils.tstest/modules/core/lib/deck.spec.tstest/modules/core/lib/deck-picker.spec.tsNote
Medium Risk
Moderate risk because it rewires core canvas resize/DPR/picking plumbing and changes
onResizecallback signature; regressions could affect rendering size, interleaved integrations, or pick accuracy across devices/contexts.Overview
Deck now treats luma.gl
CanvasContextas the authority for canvas CSS size, drawing-buffer size, DPR conversion, and resize events.Deckstores the active canvas context, routes resize handling through a new internal_onCanvasContextResize, updateswidth/heightfromcanvasContext.getCSSSize(), and takes ownership ofdevice.props.onResizewhile active (restoring it onfinalize).Picking is updated to be context-aware.
DeckPickeraccepts an optionalcanvasContextfor pick operations, sizes picking FBOs fromcanvasContext.getDrawingBufferSize(), and uses the context’s CSS-to-device conversions to compute device coordinates.Docs/tests/integrations are adjusted accordingly:
DeckProps.onResizenow also receives theCanvasContext; Google Maps/Mapbox notes and style plumbing are tweaked for shared-canvas scenarios; React utils tighten element detection/types;Layerpicking color cache is regenerated when an invalid/zeroed cache is detected; and new tests cover drawing-buffer-based picking buffer sizing plus resize/DPR forwarding behavior.Reviewed by Cursor Bugbot for commit fb12200. Bugbot is set up for automated code reviews on this repo. Configure here.