Skip to content

Commit a3224c9

Browse files
authored
feat(layers): Port ScatterplotLayer to WebGPU / WGSL (#9432)
1 parent db5e27f commit a3224c9

File tree

9 files changed

+67
-15
lines changed

9 files changed

+67
-15
lines changed

examples/website/point-cloud/app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {PointCloudLayer} from '@deck.gl/layers';
1111

1212
import {LASWorkerLoader} from '@loaders.gl/las';
1313
import type {OrbitViewState} from '@deck.gl/core';
14-
import {Device, log} from '@luma.gl/core';
14+
import {Device} from '@luma.gl/core';
1515

1616
// TODO - export from loaders?
1717
type LASMesh = (typeof LASWorkerLoader)['dataType'];

examples/website/scatterplot/app.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import {DeckGL} from '@deck.gl/react';
99
import {ScatterplotLayer} from '@deck.gl/layers';
1010

1111
import type {Color, MapViewState} from '@deck.gl/core';
12+
import type {Device, DeviceProps} from '@luma.gl/core';
1213

13-
const MALE_COLOR: Color = [0, 128, 255];
14-
const FEMALE_COLOR: Color = [255, 0, 128];
14+
const MALE_COLOR: Color = [0, 128, 255, 255];
15+
const FEMALE_COLOR: Color = [255, 0, 128, 255];
1516

1617
// Source data CSV
1718
const DATA_URL =
@@ -29,12 +30,16 @@ const INITIAL_VIEW_STATE: MapViewState = {
2930
type DataPoint = [longitude: number, latitude: number, gender: number];
3031

3132
export default function App({
33+
device,
34+
deviceProps,
3235
data = DATA_URL,
3336
radius = 30,
3437
maleColor = MALE_COLOR,
3538
femaleColor = FEMALE_COLOR,
3639
mapStyle = 'https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json'
3740
}: {
41+
device?: Device;
42+
deviceProps?: DeviceProps;
3843
data?: string | DataPoint[];
3944
radius?: number;
4045
maleColor?: Color;
@@ -52,17 +57,24 @@ export default function App({
5257
getRadius: 1,
5358
updateTriggers: {
5459
getFillColor: [maleColor, femaleColor]
55-
}
60+
},
61+
pickable: true
5662
})
5763
];
5864

5965
return (
60-
<DeckGL layers={layers} initialViewState={INITIAL_VIEW_STATE} controller={true}>
66+
<DeckGL
67+
device={device}
68+
deviceProps={deviceProps}
69+
layers={layers}
70+
initialViewState={INITIAL_VIEW_STATE}
71+
controller={true}
72+
>
6173
<Map reuseMaps mapStyle={mapStyle} />
6274
</DeckGL>
6375
);
6476
}
6577

66-
export function renderToDOM(container: HTMLDivElement) {
67-
createRoot(container).render(<App />);
78+
export function renderToDOM(container: HTMLDivElement, device?: Device, deviceProps?: DeviceProps) {
79+
createRoot(container).render(<App deviceProps={deviceProps} />);
6880
}

examples/website/scatterplot/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
</body>
1515
<script type="module">
1616
import {renderToDOM} from './app.tsx';
17-
renderToDOM(document.getElementById('app'));
17+
import {webgpuAdapter} from '@luma.gl/webgpu';
18+
renderToDOM(document.getElementById('app'), undefined, {adapters: [webgpuAdapter], type: 'webgl'});
1819
</script>
1920
</html>

examples/website/scatterplot/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"dependencies": {
1212
"@types/react": "^18.0.0",
1313
"@types/react-dom": "^18.0.0",
14-
"deck.gl": "^9.0.0",
14+
"deck.gl": "^9.2.0-alpha.2",
1515
"maplibre-gl": "^5.0.0",
1616
"react": "^18.0.0",
1717
"react-dom": "^18.0.0",

modules/core/src/lib/deck.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,16 +374,29 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
374374

375375
// Create a new device
376376
if (!deviceOrPromise) {
377+
const canvasContextUserProps = this.props.deviceProps?.createCanvasContext;
378+
const canvasContextProps =
379+
typeof canvasContextUserProps === 'object' ? canvasContextUserProps : undefined;
380+
381+
// In deck.gl v9, Deck always bundles and adds a webgl2Adapter.
382+
// This behavior is expected to change in deck.gl v10 to support WebGPU only builds.
383+
const deviceProps = {adapters: [], ...props.deviceProps};
384+
if (!deviceProps.adapters.includes(webgl2Adapter)) {
385+
deviceProps.adapters.push(webgl2Adapter);
386+
}
387+
377388
// Create the "best" device supported from the registered adapters
378389
deviceOrPromise = luma.createDevice({
379-
type: 'webgl',
380390
// luma by default throws if a device is already attached
381391
// asynchronous device creation could happen after finalize() is called
382392
// TODO - createDevice should support AbortController?
383393
_reuseDevices: true,
384-
adapters: [webgl2Adapter],
385-
...props.deviceProps,
394+
// tests can't handle WebGPU devices yet so we force WebGL2 unless overridden
395+
type: 'webgl',
396+
...deviceProps,
397+
// In deck.gl v10 we may emphasize multi canvas support and unwind this prop wrapping
386398
createCanvasContext: {
399+
...canvasContextProps,
387400
canvas: this._createCanvas(props),
388401
useDevicePixels: this.props.useDevicePixels,
389402
autoResize: true

modules/layers/src/line-layer/line-layer.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
UpdateParameters,
1717
DefaultProps
1818
} from '@deck.gl/core';
19+
import {Parameters} from '@luma.gl/core';
1920
import {Model, Geometry} from '@luma.gl/engine';
2021

2122
import {lineUniforms, LineProps} from './line-layer-uniforms';
@@ -188,6 +189,15 @@ export default class LineLayer<DataT = any, ExtraProps extends {} = {}> extends
188189
}
189190

190191
protected _getModel(): Model {
192+
// TODO(ibgreen): WebGPU complication: Matching attachment state of the renderpass requires including a depth buffer
193+
const parameters =
194+
this.context.device.type === 'webgpu'
195+
? ({
196+
depthWriteEnabled: true,
197+
depthCompare: 'less-equal'
198+
} satisfies Parameters)
199+
: undefined;
200+
191201
/*
192202
* (0, -1)-------------_(1, -1)
193203
* | _,-" |
@@ -207,6 +217,7 @@ export default class LineLayer<DataT = any, ExtraProps extends {} = {}> extends
207217
positions: {size: 3, value: new Float32Array(positions)}
208218
}
209219
}),
220+
parameters,
210221
isInstanced: true
211222
});
212223
}

modules/layers/src/scatterplot-layer/scatterplot-layer.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type {
2020
Color,
2121
DefaultProps
2222
} from '@deck.gl/core';
23+
import {Parameters} from '@luma.gl/core';
2324

2425
const DEFAULT_COLOR: [number, number, number, number] = [0, 0, 0, 255];
2526

@@ -257,10 +258,23 @@ export default class ScatterplotLayer<DataT = any, ExtraPropsT extends {} = {}>
257258
};
258259
const model = this.state.model!;
259260
model.shaderInputs.setProps({scatterplot: scatterplotProps});
261+
if (this.context.device.type === 'webgpu') {
262+
// @ts-expect-error TODO - this line was needed during WebGPU port
263+
model.instanceCount = this.props.data.length;
264+
}
260265
model.draw(this.context.renderPass);
261266
}
262267

263268
protected _getModel() {
269+
// TODO(ibgreen): WebGPU complication: Matching attachment state of the renderpass requires including a depth buffer
270+
const parameters =
271+
this.context.device.type === 'webgpu'
272+
? ({
273+
depthWriteEnabled: true,
274+
depthCompare: 'less-equal'
275+
} satisfies Parameters)
276+
: undefined;
277+
264278
// a square that minimally cover the unit circle
265279
const positions = [-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0];
266280
return new Model(this.context.device, {
@@ -273,7 +287,8 @@ export default class ScatterplotLayer<DataT = any, ExtraPropsT extends {} = {}>
273287
positions: {size: 3, value: new Float32Array(positions)}
274288
}
275289
}),
276-
isInstanced: true
290+
isInstanced: true,
291+
parameters
277292
});
278293
}
279294
}

test/apps/webgpu-line/app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export default function App({
103103
return (
104104
<DeckGL
105105
deviceProps={{
106-
adapters: [webgpuAdapter]
106+
adapters: []
107107
// onError: (error) => {
108108
// debugger
109109
// }

test/apps/webgpu-scatterplot/app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default function App({
9292
<DeckGL
9393
deviceProps={{
9494
createCanvasContext: {alphaMode: 'premultiplied'},
95-
adapters: [webgpuAdapter]
95+
adapters: []
9696
}}
9797
layers={layers}
9898
initialViewState={INITIAL_VIEW_STATE}

0 commit comments

Comments
 (0)