Skip to content

feat(layers): Port ScatterplotLayer to WebGPU / WGSL #9432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions modules/core/src/lib/deck.ts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ import {deepEqual} from '../utils/deep-equal';
import typedArrayManager from '../utils/typed-array-manager';
import {VERSION} from './init';

import {luma} from '@luma.gl/core';
import {luma, Adapter} from '@luma.gl/core';
import {webgl2Adapter} from '@luma.gl/webgl';
import {Timeline} from '@luma.gl/engine';
import {AnimationLoop} from '@luma.gl/engine';
@@ -117,6 +117,9 @@ export type DeckProps<ViewsT extends ViewOrViews = null> = {
/** Use an existing luma.gl GPU device. @note If not supplied, a new device will be created using props.deviceProps */
device?: Device | null;

/** Supply adapters to use when a new device is created */
adapters?: Adapter[];

/** A new device will be created using these props, assuming that an existing device is not supplied using props.device) */
deviceProps?: CreateDeviceProps;

@@ -373,16 +376,21 @@ export default class Deck<ViewsT extends ViewOrViews = null> {

// Create a new device
if (!deviceOrPromise) {
const canvasContextUserProps = this.props.deviceProps?.createCanvasContext;
const canvasContextProps =
typeof canvasContextUserProps === 'object' ? canvasContextUserProps : undefined;
// Create the "best" device supported from the registered adapters
const adapters = Array.from(new Set([...(props.adapters || []), webgl2Adapter]));
deviceOrPromise = luma.createDevice({
type: 'best-available',
// luma by default throws if a device is already attached
// asynchronous device creation could happen after finalize() is called
// TODO - createDevice should support AbortController?
_reuseDevices: true,
adapters: [webgl2Adapter],
adapters,
...props.deviceProps,
createCanvasContext: {
...canvasContextProps,
canvas: this._createCanvas(props),
useDevicePixels: this.props.useDevicePixels,
// TODO v9.2 - replace AnimationLoop's `autoResizeDrawingBuffer` with CanvasContext's `autoResize`
11 changes: 11 additions & 0 deletions modules/layers/src/line-layer/line-layer.ts
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ import {
UpdateParameters,
DefaultProps
} from '@deck.gl/core';
import {Parameters} from '@luma.gl/core';
import {Model, Geometry} from '@luma.gl/engine';

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

protected _getModel(): Model {
// TODO(ibgreen): WebGPU complication: Matching attachment state of the renderpass requires including a depth buffer
const parameters =
this.context.device.type === 'webgpu'
? ({
depthWriteEnabled: true,
depthCompare: 'less-equal'
} satisfies Parameters)
: undefined;

/*
* (0, -1)-------------_(1, -1)
* | _,-" |
@@ -207,6 +217,7 @@ export default class LineLayer<DataT = any, ExtraProps extends {} = {}> extends
positions: {size: 3, value: new Float32Array(positions)}
}
}),
parameters,
isInstanced: true
});
}
16 changes: 15 additions & 1 deletion modules/layers/src/scatterplot-layer/scatterplot-layer.ts
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ import type {
Color,
DefaultProps
} from '@deck.gl/core';
import {Parameters} from '@luma.gl/core';

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

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

protected _getModel() {
// TODO(ibgreen): WebGPU complication: Matching attachment state of the renderpass requires including a depth buffer
const parameters =
this.context.device.type === 'webgpu'
? ({
depthWriteEnabled: true,
depthCompare: 'less-equal'
} satisfies Parameters)
: undefined;

// a square that minimally cover the unit circle
const positions = [-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0];
return new Model(this.context.device, {
@@ -273,7 +287,7 @@ export default class ScatterplotLayer<DataT = any, ExtraPropsT extends {} = {}>
positions: {size: 3, value: new Float32Array(positions)}
}
}),
isInstanced: true
parameters
});
}
}

Unchanged files with check annotations Beta

const geojsonDatasetIds = geojsonLayers.map(({config}) => config.dataId);
map.datasets.forEach(dataset => {
if (geojsonDatasetIds.includes(dataset.id)) {
const {config} = geojsonLayers.find(({config}) => config.dataId === dataset.id);

Check warning on line 320 in modules/carto/src/api/fetch-map.ts

GitHub Actions / test-node

'config' is already declared in the upper scope on line 320 column 14
dataset.format = 'geojson';
// Support for very old maps. geoColumn was not stored in the past
if (!dataset.geoColumn && config.columns.geojson) {
import {Texture} from '@luma.gl/core';
import {Model, Geometry} from '@luma.gl/engine';
import {Layer, picking, UpdateParameters, DefaultProps, Color} from '@deck.gl/core';

Check warning on line 7 in modules/aggregation-layers/src/screen-grid-layer/screen-grid-cell-layer.ts

GitHub Actions / test-node

'DefaultProps' is defined but never used
import {createColorRangeTexture, updateColorRangeTexture} from '../common/utils/color-utils';
import vs from './screen-grid-layer-vertex.glsl';
import fs from './screen-grid-layer-fragment.glsl';
});
}
updateState(params: UpdateParameters<this>) {

Check warning on line 376 in modules/aggregation-layers/src/hexagon-layer/hexagon-layer.ts

GitHub Actions / test-node

Method 'updateState' has a complexity of 19. Maximum allowed is 11
const aggregatorChanged = super.updateState(params);
const {props, oldProps, changeFlags} = params;
});
}
updateState(params: UpdateParameters<this>) {

Check warning on line 371 in modules/aggregation-layers/src/grid-layer/grid-layer.ts

GitHub Actions / test-node

Method 'updateState' has a complexity of 19. Maximum allowed is 11
const aggregatorChanged = super.updateState(params);
const {props, oldProps, changeFlags} = params;
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import {ModelProps} from '@luma.gl/engine';

Check warning on line 5 in modules/aggregation-layers/src/common/aggregator/gpu-aggregator/webgl-aggregator.ts

GitHub Actions / test-node

'ModelProps' is defined but never used
import {WebGLBinSorter} from './webgl-bin-sorter';
import {WebGLAggregationTransform} from './webgl-aggregation-transform';
import {_deepEqual as deepEqual, log, BinaryAttribute} from '@deck.gl/core';
}
/** Update aggregation props. Normalize prop values and set change flags. */
setProps(props: Partial<WebGLAggregationProps>) {

Check warning on line 172 in modules/aggregation-layers/src/common/aggregator/gpu-aggregator/webgl-aggregator.ts

GitHub Actions / test-node

Method 'setProps' has a complexity of 17. Maximum allowed is 11

Check warning on line 172 in modules/aggregation-layers/src/common/aggregator/gpu-aggregator/webgl-aggregator.ts

GitHub Actions / test-node

Method 'setProps' has too many statements (35). Maximum allowed is 25
const oldProps = this.props;
// Update local settings. These will set the flag this._needsUpdate
}
/** Update aggregation props */
setProps(props: Partial<CPUAggregationProps>) {

Check warning on line 78 in modules/aggregation-layers/src/common/aggregator/cpu-aggregator/cpu-aggregator.ts

GitHub Actions / test-node

Method 'setProps' has a complexity of 12. Maximum allowed is 11
const oldProps = this.props;
if (props.binOptions) {
if (!target || target.length < bins.length) {
target = new Float32Array(bins.length);
}
let min = Infinity;

Check warning on line 90 in modules/aggregation-layers/src/common/aggregator/cpu-aggregator/aggregate.ts

GitHub Actions / test-node

'min' is already declared in the upper scope on line 35 column 7
let max = -Infinity;

Check warning on line 91 in modules/aggregation-layers/src/common/aggregator/cpu-aggregator/aggregate.ts

GitHub Actions / test-node

'max' is already declared in the upper scope on line 46 column 7
for (let j = 0; j < bins.length; j++) {
const {points} = bins[j];