Skip to content

Commit 021897b

Browse files
ibgreenchrisgervang
authored andcommitted
chore(core) Adopt luma CanvasContext (#10228)
1 parent a277344 commit 021897b

13 files changed

Lines changed: 471 additions & 110 deletions

File tree

AGENTS.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Repository Guidance
2+
3+
This file applies to the entire `deck.gl` repository. More specific `AGENTS.md` files in
4+
subdirectories may add local guidance.
5+
6+
## Setup Commands
7+
8+
- Install dependencies from the repo root: `yarn`
9+
- Build packages: `yarn build`
10+
- Run lint: `yarn lint`
11+
- Run all tests: `yarn test`
12+
- Run headless tests: `yarn test-headless`
13+
- Run render tests: `yarn test-render`
14+
- Run browser tests: `yarn test-browser`
15+
- Run website checks: `yarn test-website`
16+
- Use the exact script names from `package.json`; do not substitute spaced forms such as
17+
`yarn test headless`.
18+
19+
## Before Committing
20+
21+
- Run the most relevant tests for the changed packages, integrations, examples, or docs.
22+
- Run `yarn lint` for JavaScript and TypeScript changes. If lint failures are unrelated existing
23+
issues, call that out explicitly instead of hiding it.
24+
- If dependencies or package metadata changed, run `yarn` in the repo root and include any
25+
`yarn.lock` updates.
26+
- Do not reformat files you are not otherwise changing. Keep formatting-only churn separate from
27+
logic changes when practical.
28+
29+
## Ready For Merge
30+
31+
When asked to "get ready for merge", do a full merge-readiness pass:
32+
33+
- Audit the public API surface touched by the change. Add or update TSDoc for every new or changed
34+
public class, function, method, property, and type.
35+
- Do a documentation pass when behavior, public API, examples, or migration guidance changed.
36+
Include relevant module docs, examples, sidebars, `docs/whats-new.md`, and upgrade or migration
37+
guide content.
38+
- Keep upgrade guides focused on breaking changes, removals, and deprecations. Put new-feature
39+
notes in the appropriate module docs or release notes instead.
40+
- Run `yarn` in the repo root so workspace metadata and `yarn.lock` are up to date, especially
41+
after any `package.json` change.
42+
- Run `yarn build` as the repo-wide type, declaration, and package build gate.
43+
- Run `yarn lint` for the final lint and formatting gate, then review the resulting diff.
44+
- Run the relevant tests for the changed packages, examples, integrations, and docs/website wiring.
45+
Typical commands are `yarn test`, `yarn test-headless`, `yarn test-render`, `yarn test-browser`,
46+
and `yarn test-website`.
47+
- For website or docs changes, run the website check from the repo root with `yarn test-website`.
48+
- Prepare a copyable Markdown PR description based on the branch diff compared to `master`. Start
49+
with the PR goals, then list the actual changes and validation.
50+
- In the final handoff, call out which merge-readiness gates passed, which were not run, and any
51+
remaining risk or unrelated pre-existing failures.
52+
53+
## Code Style
54+
55+
- Prefer TypeScript and ES module syntax.
56+
- Match the surrounding file style. In source files, use single quotes and semicolons.
57+
- Never abbreviate variable names. Use camelCase for variables, functions, and fields; PascalCase
58+
for types and classes; and CAPITAL_CASE for constants.
59+
- Prefer verb-noun names for functions and methods.
60+
- File names should be kebab-case unless an existing local convention differs.
61+
62+
## Dependencies
63+
64+
- Be conservative with new external dependencies. Add one only when it provides meaningful
65+
capability, not just a small utility.
66+
- Prefer vis.gl ecosystem packages when they fit the layering. Lower-level math or utility modules
67+
should not depend on deck.gl.
68+
- Prefer math.gl modules for math helpers.
69+
- Avoid lodash-style dependencies for simple operations.
70+
71+
## Investigation
72+
73+
- Do not fix problems by adding caches. Investigate why the problem occurs and address the root
74+
cause.

docs/api-reference/core/deck.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ The canvas to render into. Can be either a HTMLCanvasElement or the element id.
5252

5353
luma.gl Device used to manage the application's connection with the GPU. Will be auto-created if not supplied.
5454

55+
When a `Device` is supplied, Deck does not destroy it when finalized. While the `Deck` instance is active, Deck owns the `device.props.onResize` callback for the active render canvas context; use `DeckProps.onResize` to observe Deck canvas resizes.
56+
5557
#### `deviceProps` ([DeviceProps](https://luma.gl/docs/api-reference/core/device#deviceprops) | [WebGLDeviceProps](https://luma.gl/docs/api-reference/webgl/#webgldeviceprops)) {#deviceprops}
5658

5759
Options used for creating a new luma.gl GPU [Device](https://luma.gl/docs/api-reference/core/device).
@@ -551,6 +553,7 @@ Receives arguments:
551553
* `size`
552554
- `width` (number) - the new width of the deck canvas, in client pixels
553555
- `height` (number) - the new height of the deck canvas, in client pixels
556+
* `canvasContext` ([CanvasContext](https://luma.gl/docs/api-reference/core/canvas-context), optional) - the luma.gl canvas context that reported the resize
554557
555558
556559
#### `onBeforeRender` (Function) {#onbeforerender}

modules/core/src/lib/deck-picker.ts

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Copyright (c) vis.gl contributors
44

55
import {Buffer, Texture} from '@luma.gl/core';
6-
import type {Device} from '@luma.gl/core';
6+
import type {CanvasContext, Device} from '@luma.gl/core';
77
import PickLayersPass, {PickingColorDecoder} from '../passes/pick-layers-pass';
88
import log from '../utils/log';
99
import {getClosestObject, getUniqueObjects, PickedPixel} from './picking/query-object';
@@ -44,6 +44,7 @@ type PickOperationContext = {
4444
layers: Layer[];
4545
views: Record<string, View>;
4646
viewports: Viewport[];
47+
canvasContext?: CanvasContext;
4748
onViewportActive: (viewport: Viewport) => void;
4849
effects: Effect[];
4950
};
@@ -157,7 +158,7 @@ export default class DeckPicker {
157158
// Private
158159

159160
/** Ensures that picking framebuffer exists and matches the canvas size */
160-
_resizeBuffer() {
161+
_resizeBuffer(canvasContext: CanvasContext = this.device.getDefaultCanvasContext()) {
161162
// Create a frame buffer if not already available
162163
if (!this.pickingFBO) {
163164
const pickingColorTexture = this.device.createTexture({
@@ -186,10 +187,11 @@ export default class DeckPicker {
186187
}
187188
}
188189

189-
// Resize it to current canvas size (this is a noop if size hasn't changed)
190-
const {canvas} = this.device.getDefaultCanvasContext();
191-
this.pickingFBO?.resize({width: canvas.width, height: canvas.height});
192-
this.depthFBO?.resize({width: canvas.width, height: canvas.height});
190+
// Picking renders in drawing-buffer pixels. DPR and useDevicePixels can make that size
191+
// differ from the canvas/CSS size used for viewport bookkeeping.
192+
const [width, height] = canvasContext.getDrawingBufferSize();
193+
this.pickingFBO?.resize({width, height});
194+
this.depthFBO?.resize({width, height});
193195
}
194196

195197
/** Preliminary filtering of the layers list. Skid picking pass if no layer is pickable. */
@@ -217,14 +219,15 @@ export default class DeckPicker {
217219
depth = 1,
218220
mode = 'query',
219221
unproject3D,
222+
canvasContext = this.device.getDefaultCanvasContext(),
220223
onViewportActive,
221224
effects
222225
}: PickByPointOptions & PickOperationContext): Promise<{
223226
result: PickingInfo[];
224227
emptyInfo: PickingInfo;
225228
}> {
226-
// @ts-expect-error TODO - assuming WebGL context
227-
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
229+
// Picking starts in CSS pixels, so use the canvas context's current conversion ratio.
230+
const pixelRatio = canvasContext.cssToDeviceRatio();
228231

229232
const pickableLayers = this._getPickable(layers);
230233

@@ -235,13 +238,12 @@ export default class DeckPicker {
235238
};
236239
}
237240

238-
this._resizeBuffer();
241+
this._resizeBuffer(canvasContext);
239242

240243
// Convert from canvas top-left to WebGL bottom-left coordinates
241244
// Top-left coordinates [x, y] to bottom-left coordinates [deviceX, deviceY]
242-
// And compensate for pixelRatio
243-
// @ts-expect-error TODO - assuming WebGL context
244-
const devicePixelRange = this.device.canvasContext.cssToDevicePixels([x, y], true);
245+
// And compensate for the context's current CSS-to-device ratio.
246+
const devicePixelRange = canvasContext.cssToDevicePixels([x, y], true);
245247
const devicePixel = [
246248
devicePixelRange.x + Math.floor(devicePixelRange.width / 2),
247249
devicePixelRange.y + Math.floor(devicePixelRange.height / 2)
@@ -381,14 +383,15 @@ export default class DeckPicker {
381383
depth = 1,
382384
mode = 'query',
383385
unproject3D,
386+
canvasContext = this.device.getDefaultCanvasContext(),
384387
onViewportActive,
385388
effects
386389
}: PickByPointOptions & PickOperationContext): {
387390
result: PickingInfo[];
388391
emptyInfo: PickingInfo;
389392
} {
390-
// @ts-expect-error TODO - assuming WebGL context
391-
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
393+
// Keep the sync picking path aligned with the same canvas context state used for drawing.
394+
const pixelRatio = canvasContext.cssToDeviceRatio();
392395

393396
const pickableLayers = this._getPickable(layers);
394397

@@ -399,13 +402,12 @@ export default class DeckPicker {
399402
};
400403
}
401404

402-
this._resizeBuffer();
405+
this._resizeBuffer(canvasContext);
403406

404407
// Convert from canvas top-left to WebGL bottom-left coordinates
405408
// Top-left coordinates [x, y] to bottom-left coordinates [deviceX, deviceY]
406-
// And compensate for pixelRatio
407-
// @ts-expect-error TODO - assuming WebGL context
408-
const devicePixelRange = this.device.canvasContext.cssToDevicePixels([x, y], true);
409+
// And compensate for the context's current CSS-to-device ratio.
410+
const devicePixelRange = canvasContext.cssToDevicePixels([x, y], true);
409411
const devicePixel = [
410412
devicePixelRange.x + Math.floor(devicePixelRange.width / 2),
411413
devicePixelRange.y + Math.floor(devicePixelRange.height / 2)
@@ -544,6 +546,7 @@ export default class DeckPicker {
544546
height = 1,
545547
mode = 'query',
546548
maxObjects = null,
549+
canvasContext = this.device.getDefaultCanvasContext(),
547550
onViewportActive,
548551
effects
549552
}: PickByRectOptions & PickOperationContext): Promise<PickingInfo[]> {
@@ -553,22 +556,19 @@ export default class DeckPicker {
553556
return [];
554557
}
555558

556-
this._resizeBuffer();
559+
this._resizeBuffer(canvasContext);
557560

558561
// Convert from canvas top-left to WebGL bottom-left coordinates
559-
// And compensate for pixelRatio
560-
// @ts-expect-error TODO - assuming WebGL context
561-
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
562-
// @ts-expect-error TODO - assuming WebGL context
563-
const leftTop = this.device.canvasContext.cssToDevicePixels([x, y], true);
562+
// And compensate for the context's current CSS-to-device ratio.
563+
const pixelRatio = canvasContext.cssToDeviceRatio();
564+
const leftTop = canvasContext.cssToDevicePixels([x, y], true);
564565

565566
// take left and top (y inverted in device pixels) from start location
566567
const deviceLeft = leftTop.x;
567568
const deviceTop = leftTop.y + leftTop.height;
568569

569570
// take right and bottom (y inverted in device pixels) from end location
570-
// @ts-expect-error TODO - assuming WebGL context
571-
const rightBottom = this.device.canvasContext.cssToDevicePixels([x + width, y + height], true);
571+
const rightBottom = canvasContext.cssToDevicePixels([x + width, y + height], true);
572572
const deviceRight = rightBottom.x + rightBottom.width;
573573
const deviceBottom = rightBottom.y;
574574

@@ -651,6 +651,7 @@ export default class DeckPicker {
651651
height = 1,
652652
mode = 'query',
653653
maxObjects = null,
654+
canvasContext = this.device.getDefaultCanvasContext(),
654655
onViewportActive,
655656
effects
656657
}: PickByRectOptions & PickOperationContext): PickingInfo[] {
@@ -660,22 +661,19 @@ export default class DeckPicker {
660661
return [];
661662
}
662663

663-
this._resizeBuffer();
664+
this._resizeBuffer(canvasContext);
664665

665666
// Convert from canvas top-left to WebGL bottom-left coordinates
666-
// And compensate for pixelRatio
667-
// @ts-expect-error TODO - assuming WebGL context
668-
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
669-
// @ts-expect-error TODO - assuming WebGL context
670-
const leftTop = this.device.canvasContext.cssToDevicePixels([x, y], true);
667+
// And compensate for the context's current CSS-to-device ratio.
668+
const pixelRatio = canvasContext.cssToDeviceRatio();
669+
const leftTop = canvasContext.cssToDevicePixels([x, y], true);
671670

672671
// take left and top (y inverted in device pixels) from start location
673672
const deviceLeft = leftTop.x;
674673
const deviceTop = leftTop.y + leftTop.height;
675674

676675
// take right and bottom (y inverted in device pixels) from end location
677-
// @ts-expect-error TODO - assuming WebGL context
678-
const rightBottom = this.device.canvasContext.cssToDevicePixels([x + width, y + height], true);
676+
const rightBottom = canvasContext.cssToDevicePixels([x + width, y + height], true);
679677
const deviceRight = rightBottom.x + rightBottom.width;
680678
const deviceBottom = rightBottom.y;
681679

0 commit comments

Comments
 (0)