@luma.gl/webgpu 9.0.0-alpha.9 → 9.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -1
- package/dist/adapter/helpers/accessor-to-format.js +102 -1
- package/dist/adapter/helpers/convert-texture-format.d.ts +2 -2
- package/dist/adapter/helpers/convert-texture-format.d.ts.map +1 -1
- package/dist/adapter/helpers/convert-texture-format.js +8 -6
- package/dist/adapter/helpers/get-bind-group.d.ts +4 -4
- package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
- package/dist/adapter/helpers/get-bind-group.js +61 -52
- package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts +5 -5
- package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
- package/dist/adapter/helpers/get-vertex-buffer-layout.js +123 -90
- package/dist/adapter/helpers/webgpu-parameters.d.ts +2 -2
- package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -1
- package/dist/adapter/helpers/webgpu-parameters.js +184 -130
- package/dist/adapter/resources/webgpu-buffer.d.ts +14 -5
- package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-buffer.js +117 -70
- package/dist/adapter/resources/webgpu-command-encoder.d.ts +13 -14
- package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-command-encoder.js +83 -65
- package/dist/adapter/resources/webgpu-compute-pass.d.ts +19 -13
- package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pass.js +78 -57
- package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +16 -6
- package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pipeline.js +48 -26
- package/dist/adapter/resources/webgpu-external-texture.d.ts +5 -5
- package/dist/adapter/resources/webgpu-external-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-external-texture.js +38 -29
- package/dist/adapter/resources/webgpu-framebuffer.d.ts +4 -21
- package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-framebuffer.js +15 -109
- package/dist/adapter/resources/webgpu-query-set.d.ts +17 -0
- package/dist/adapter/resources/webgpu-query-set.d.ts.map +1 -0
- package/dist/adapter/resources/webgpu-query-set.js +27 -0
- package/dist/adapter/resources/webgpu-render-pass.d.ts +14 -7
- package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pass.js +136 -91
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts +63 -23
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pipeline.js +151 -148
- package/dist/adapter/resources/webgpu-sampler.d.ts +5 -5
- package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-sampler.js +23 -23
- package/dist/adapter/resources/webgpu-shader.d.ts +9 -12
- package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-shader.js +47 -60
- package/dist/adapter/resources/webgpu-texture-view.d.ts +20 -0
- package/dist/adapter/resources/webgpu-texture-view.d.ts.map +1 -0
- package/dist/adapter/resources/webgpu-texture-view.js +35 -0
- package/dist/adapter/resources/webgpu-texture.d.ts +20 -10
- package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-texture.js +133 -105
- package/dist/adapter/resources/webgpu-vertex-array.d.ts +27 -0
- package/dist/adapter/resources/webgpu-vertex-array.d.ts.map +1 -0
- package/dist/adapter/resources/webgpu-vertex-array.js +66 -0
- package/dist/adapter/webgpu-canvas-context.d.ts +17 -12
- package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
- package/dist/adapter/webgpu-canvas-context.js +105 -92
- package/dist/adapter/webgpu-device.d.ts +45 -30
- package/dist/adapter/webgpu-device.d.ts.map +1 -1
- package/dist/adapter/webgpu-device.js +266 -241
- package/dist/dist.dev.js +1664 -0
- package/dist/dist.min.js +9 -0
- package/dist/index.cjs +1432 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -8
- package/dist.min.js +9 -0
- package/package.json +22 -11
- package/src/adapter/helpers/accessor-to-format.ts +6 -3
- package/src/adapter/helpers/convert-texture-format.ts +5 -2
- package/src/adapter/helpers/get-bind-group.ts +30 -14
- package/src/adapter/helpers/get-vertex-buffer-layout.ts +73 -39
- package/src/adapter/helpers/webgpu-parameters.ts +99 -29
- package/src/adapter/resources/webgpu-buffer.ts +85 -17
- package/src/adapter/resources/webgpu-command-encoder.ts +93 -58
- package/src/adapter/resources/webgpu-compute-pass.ts +56 -32
- package/src/adapter/resources/webgpu-compute-pipeline.ts +51 -18
- package/src/adapter/resources/webgpu-external-texture.ts +19 -11
- package/src/adapter/resources/webgpu-framebuffer.ts +11 -108
- package/src/adapter/resources/webgpu-query-set.ts +37 -0
- package/src/adapter/resources/webgpu-render-pass.ts +95 -19
- package/src/adapter/resources/webgpu-render-pipeline.ts +139 -159
- package/src/adapter/resources/webgpu-sampler.ts +10 -7
- package/src/adapter/resources/webgpu-shader.ts +30 -35
- package/src/adapter/resources/webgpu-texture-view.ts +46 -0
- package/src/adapter/resources/webgpu-texture.ts +75 -41
- package/src/adapter/resources/webgpu-vertex-array.ts +91 -0
- package/src/adapter/webgpu-canvas-context.ts +60 -29
- package/src/adapter/webgpu-device.ts +219 -120
- package/src/index.ts +8 -9
- package/dist/adapter/helpers/accessor-to-format.js.map +0 -1
- package/dist/adapter/helpers/convert-texture-format.js.map +0 -1
- package/dist/adapter/helpers/generate-mipmaps.d.ts +0 -10
- package/dist/adapter/helpers/generate-mipmaps.d.ts.map +0 -1
- package/dist/adapter/helpers/generate-mipmaps.js +0 -95
- package/dist/adapter/helpers/generate-mipmaps.js.map +0 -1
- package/dist/adapter/helpers/get-bind-group.js.map +0 -1
- package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +0 -1
- package/dist/adapter/helpers/webgpu-parameters.js.map +0 -1
- package/dist/adapter/resources/webgpu-buffer.js.map +0 -1
- package/dist/adapter/resources/webgpu-command-encoder.js.map +0 -1
- package/dist/adapter/resources/webgpu-compute-pass.js.map +0 -1
- package/dist/adapter/resources/webgpu-compute-pipeline.js.map +0 -1
- package/dist/adapter/resources/webgpu-external-texture.js.map +0 -1
- package/dist/adapter/resources/webgpu-framebuffer.js.map +0 -1
- package/dist/adapter/resources/webgpu-query.d.ts +0 -1
- package/dist/adapter/resources/webgpu-query.d.ts.map +0 -1
- package/dist/adapter/resources/webgpu-query.js +0 -2
- package/dist/adapter/resources/webgpu-query.js.map +0 -1
- package/dist/adapter/resources/webgpu-render-pass.js.map +0 -1
- package/dist/adapter/resources/webgpu-render-pipeline.js.map +0 -1
- package/dist/adapter/resources/webgpu-sampler.js.map +0 -1
- package/dist/adapter/resources/webgpu-shader.js.map +0 -1
- package/dist/adapter/resources/webgpu-texture.js.map +0 -1
- package/dist/adapter/webgpu-canvas-context.js.map +0 -1
- package/dist/adapter/webgpu-device.js.map +0 -1
- package/dist/adapter/webgpu-types.d.ts +0 -1
- package/dist/adapter/webgpu-types.d.ts.map +0 -1
- package/dist/adapter/webgpu-types.js +0 -2
- package/dist/adapter/webgpu-types.js.map +0 -1
- package/dist/bundle.d.ts +0 -2
- package/dist/bundle.d.ts.map +0 -1
- package/dist/bundle.js +0 -5
- package/dist/bundle.js.map +0 -1
- package/dist/glsl/glsllang.d.ts +0 -3
- package/dist/glsl/glsllang.d.ts.map +0 -1
- package/dist/glsl/glsllang.js +0 -10
- package/dist/glsl/glsllang.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init.d.ts +0 -2
- package/dist/init.d.ts.map +0 -1
- package/dist/init.js +0 -4
- package/dist/init.js.map +0 -1
- package/src/adapter/helpers/generate-mipmaps.ts +0 -107
- package/src/adapter/resources/webgpu-query.ts +0 -43
- package/src/adapter/webgpu-types.ts +0 -0
- package/src/bundle.ts +0 -4
- package/src/glsl/glsllang.ts +0 -14
- package/src/init.ts +0 -4
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {RenderPassProps, RenderPassParameters, Binding, Framebuffer} from '@luma.gl/core';
|
|
6
|
+
import {Buffer, RenderPass, RenderPipeline, cast, log} from '@luma.gl/core';
|
|
7
|
+
import {WebGPUDevice} from '../webgpu-device';
|
|
8
|
+
import {WebGPUBuffer} from './webgpu-buffer';
|
|
9
|
+
import {WebGPUTextureView} from './webgpu-texture-view';
|
|
10
|
+
// import {WebGPUCommandEncoder} from './webgpu-command-encoder';
|
|
11
|
+
import {WebGPURenderPipeline} from './webgpu-render-pipeline';
|
|
12
|
+
import {WebGPUQuerySet} from './webgpu-query-set';
|
|
13
|
+
|
|
14
|
+
export class WebGPURenderPass extends RenderPass {
|
|
9
15
|
readonly device: WebGPUDevice;
|
|
10
16
|
readonly handle: GPURenderPassEncoder;
|
|
11
17
|
|
|
@@ -16,16 +22,35 @@ export default class WebGPURenderPass extends RenderPass {
|
|
|
16
22
|
super(device, props);
|
|
17
23
|
this.device = device;
|
|
18
24
|
const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer();
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
const renderPassDescriptor = this.getRenderPassDescriptor(framebuffer);
|
|
26
|
+
|
|
27
|
+
const webgpuQuerySet = props.timestampQuerySet as WebGPUQuerySet;
|
|
28
|
+
if (webgpuQuerySet) {
|
|
29
|
+
renderPassDescriptor.occlusionQuerySet = webgpuQuerySet.handle;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (device.features.has('timestamp-query')) {
|
|
33
|
+
const webgpuQuerySet = props.timestampQuerySet as WebGPUQuerySet;
|
|
34
|
+
renderPassDescriptor.timestampWrites = webgpuQuerySet
|
|
35
|
+
? ({
|
|
36
|
+
querySet: webgpuQuerySet.handle,
|
|
37
|
+
beginningOfPassWriteIndex: props.beginTimestampIndex,
|
|
38
|
+
endOfPassWriteIndex: props.endTimestampIndex
|
|
39
|
+
} as GPUComputePassTimestampWrites)
|
|
40
|
+
: undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
21
43
|
this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
|
|
22
44
|
this.handle.label = this.props.id;
|
|
45
|
+
log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
|
|
46
|
+
log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
|
|
47
|
+
log.groupEnd(3)();
|
|
23
48
|
}
|
|
24
49
|
|
|
25
|
-
destroy() {}
|
|
50
|
+
override destroy(): void {}
|
|
26
51
|
|
|
27
|
-
|
|
28
|
-
this.handle.
|
|
52
|
+
end(): void {
|
|
53
|
+
this.handle.end();
|
|
29
54
|
}
|
|
30
55
|
|
|
31
56
|
setPipeline(pipeline: RenderPipeline): void {
|
|
@@ -75,7 +100,7 @@ export default class WebGPURenderPass extends RenderPass {
|
|
|
75
100
|
} else {
|
|
76
101
|
this.handle.draw(
|
|
77
102
|
options.vertexCount || 0,
|
|
78
|
-
options.instanceCount,
|
|
103
|
+
options.instanceCount || 1,
|
|
79
104
|
options.firstIndex,
|
|
80
105
|
options.firstInstance
|
|
81
106
|
);
|
|
@@ -121,11 +146,62 @@ export default class WebGPURenderPass extends RenderPass {
|
|
|
121
146
|
this.handle.insertDebugMarker(markerLabel);
|
|
122
147
|
}
|
|
123
148
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
149
|
+
beginOcclusionQuery(queryIndex: number): void {
|
|
150
|
+
this.handle.beginOcclusionQuery(queryIndex);
|
|
151
|
+
}
|
|
152
|
+
endOcclusionQuery(): void {
|
|
153
|
+
this.handle.endOcclusionQuery();
|
|
154
|
+
}
|
|
129
155
|
|
|
130
156
|
// executeBundles(bundles: Iterable<GPURenderBundle>): void;
|
|
157
|
+
|
|
158
|
+
// INTERNAL
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Partial render pass descriptor. Used by WebGPURenderPass.
|
|
162
|
+
* @returns attachments fields of a renderpass descriptor.
|
|
163
|
+
*/
|
|
164
|
+
protected getRenderPassDescriptor(framebuffer: Framebuffer): GPURenderPassDescriptor {
|
|
165
|
+
const renderPassDescriptor: GPURenderPassDescriptor = {
|
|
166
|
+
colorAttachments: []
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
renderPassDescriptor.colorAttachments = framebuffer.colorAttachments.map(colorAttachment => ({
|
|
170
|
+
// clear values
|
|
171
|
+
loadOp: this.props.clearColor !== false ? 'clear' : 'load',
|
|
172
|
+
colorClearValue: this.props.clearColor || [0, 0, 0, 0],
|
|
173
|
+
storeOp: this.props.discard ? 'discard' : 'store',
|
|
174
|
+
// ...colorAttachment,
|
|
175
|
+
view: (colorAttachment as WebGPUTextureView).handle
|
|
176
|
+
}));
|
|
177
|
+
|
|
178
|
+
if (framebuffer.depthStencilAttachment) {
|
|
179
|
+
renderPassDescriptor.depthStencilAttachment = {
|
|
180
|
+
view: (framebuffer.depthStencilAttachment as WebGPUTextureView).handle
|
|
181
|
+
};
|
|
182
|
+
const {depthStencilAttachment} = renderPassDescriptor;
|
|
183
|
+
|
|
184
|
+
// DEPTH
|
|
185
|
+
if (this.props.depthReadOnly) {
|
|
186
|
+
depthStencilAttachment.depthReadOnly = true;
|
|
187
|
+
}
|
|
188
|
+
depthStencilAttachment.depthClearValue = this.props.clearDepth || 0;
|
|
189
|
+
|
|
190
|
+
// WebGPU only wants us to set these parameters if the texture format actually has a depth aspect
|
|
191
|
+
const hasDepthAspect = true;
|
|
192
|
+
if (hasDepthAspect) {
|
|
193
|
+
depthStencilAttachment.depthLoadOp = this.props.clearDepth !== false ? 'clear' : 'load';
|
|
194
|
+
depthStencilAttachment.depthStoreOp = 'store'; // TODO - support 'discard'?
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// WebGPU only wants us to set these parameters if the texture format actually has a stencil aspect
|
|
198
|
+
const hasStencilAspect = false;
|
|
199
|
+
if (hasStencilAspect) {
|
|
200
|
+
depthStencilAttachment.stencilLoadOp = this.props.clearStencil !== false ? 'clear' : 'load';
|
|
201
|
+
depthStencilAttachment.stencilStoreOp = 'store'; // TODO - support 'discard'?
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return renderPassDescriptor;
|
|
206
|
+
}
|
|
131
207
|
}
|
|
@@ -1,157 +1,179 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// luma.gl MIT license
|
|
2
|
+
|
|
3
|
+
import type {Binding, RenderPass, VertexArray} from '@luma.gl/core';
|
|
4
|
+
import {RenderPipeline, RenderPipelineProps, cast, log} from '@luma.gl/core';
|
|
3
5
|
import {applyParametersToRenderPipelineDescriptor} from '../helpers/webgpu-parameters';
|
|
4
6
|
import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
|
|
5
7
|
import {getBindGroup} from '../helpers/get-bind-group';
|
|
6
|
-
import {getVertexBufferLayout
|
|
8
|
+
import {getVertexBufferLayout} from '../helpers/get-vertex-buffer-layout';
|
|
7
9
|
// import {convertAttributesVertexBufferToLayout} from '../helpers/get-vertex-buffer-layout';
|
|
8
10
|
// import {mapAccessorToWebGPUFormat} from './helpers/accessor-to-format';
|
|
9
11
|
// import type {BufferAccessors} from './webgpu-pipeline';
|
|
10
12
|
|
|
11
|
-
import type WebGPUDevice from '../webgpu-device';
|
|
12
|
-
import type WebGPUBuffer from './webgpu-buffer';
|
|
13
|
-
import type WebGPUShader from './webgpu-shader';
|
|
14
|
-
import type WebGPURenderPass from './webgpu-render-pass';
|
|
13
|
+
import type {WebGPUDevice} from '../webgpu-device';
|
|
14
|
+
// import type {WebGPUBuffer} from './webgpu-buffer';
|
|
15
|
+
import type {WebGPUShader} from './webgpu-shader';
|
|
16
|
+
import type {WebGPURenderPass} from './webgpu-render-pass';
|
|
15
17
|
|
|
16
18
|
// RENDER PIPELINE
|
|
17
19
|
|
|
18
20
|
/** Creates a new render pipeline when parameters change */
|
|
19
|
-
export
|
|
21
|
+
export class WebGPURenderPipeline extends RenderPipeline {
|
|
20
22
|
device: WebGPUDevice;
|
|
21
23
|
handle: GPURenderPipeline;
|
|
22
24
|
|
|
23
25
|
vs: WebGPUShader;
|
|
24
26
|
fs: WebGPUShader | null = null;
|
|
25
27
|
|
|
26
|
-
private _bufferSlots: Record<string, number>;
|
|
27
|
-
private _buffers: Buffer[];
|
|
28
|
-
private _indexBuffer: WebGPUBuffer | null = null;
|
|
29
|
-
// private _firstIndex: number;
|
|
30
|
-
// private _lastIndex: number;
|
|
31
|
-
|
|
32
28
|
/** For internal use to create BindGroups */
|
|
33
|
-
private
|
|
29
|
+
private _bindings: Record<string, Binding>;
|
|
30
|
+
private _bindGroupLayout: GPUBindGroupLayout | null = null;
|
|
34
31
|
private _bindGroup: GPUBindGroup | null = null;
|
|
35
32
|
|
|
36
33
|
constructor(device: WebGPUDevice, props: RenderPipelineProps) {
|
|
37
34
|
super(device, props);
|
|
38
35
|
this.device = device;
|
|
39
|
-
this.handle =
|
|
36
|
+
this.handle = this.props.handle as GPURenderPipeline;
|
|
37
|
+
if (!this.handle) {
|
|
38
|
+
const descriptor = this._getRenderPipelineDescriptor();
|
|
39
|
+
log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
|
|
40
|
+
log.probe(1, JSON.stringify(descriptor, null, 2))();
|
|
41
|
+
log.groupEnd(1)();
|
|
42
|
+
this.handle = this.device.handle.createRenderPipeline(descriptor);
|
|
43
|
+
}
|
|
40
44
|
this.handle.label = this.props.id;
|
|
41
45
|
|
|
42
46
|
this.vs = cast<WebGPUShader>(props.vs);
|
|
43
47
|
this.fs = cast<WebGPUShader>(props.fs);
|
|
44
48
|
|
|
45
|
-
this.
|
|
46
|
-
this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
|
|
47
|
-
this._bindGroupLayout = this.handle.getBindGroupLayout(0);
|
|
49
|
+
this._bindings = {...this.props.bindings};
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
const descriptor = this._getRenderPipelineDescriptor();
|
|
52
|
-
const renderPipeline = this.device.handle.createRenderPipeline(descriptor);
|
|
53
|
-
log.groupCollapsed(1, `new WebGPRenderPipeline(${this.id})`)();
|
|
54
|
-
log.log(1, JSON.stringify(descriptor, null, 2))();
|
|
55
|
-
log.groupEnd(1)();
|
|
56
|
-
return renderPipeline;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
destroy() {
|
|
52
|
+
override destroy(): void {
|
|
60
53
|
// WebGPURenderPipeline has no destroy method.
|
|
54
|
+
this.handle = null;
|
|
61
55
|
}
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
/**
|
|
58
|
+
* @todo Use renderpass.setBindings() ?
|
|
59
|
+
* @todo Do we want to expose BindGroups in the API and remove this?
|
|
60
|
+
*/
|
|
61
|
+
setBindings(bindings: Record<string, Binding>): void {
|
|
62
|
+
Object.assign(this._bindings, bindings);
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
/** @todo - should this be moved to renderpass? */
|
|
66
|
+
draw(options: {
|
|
67
|
+
renderPass: RenderPass;
|
|
68
|
+
vertexArray: VertexArray;
|
|
69
|
+
vertexCount?: number;
|
|
70
|
+
indexCount?: number;
|
|
71
|
+
instanceCount?: number;
|
|
72
|
+
firstVertex?: number;
|
|
73
|
+
firstIndex?: number;
|
|
74
|
+
firstInstance?: number;
|
|
75
|
+
baseVertex?: number;
|
|
76
|
+
}): boolean {
|
|
77
|
+
const webgpuRenderPass = options.renderPass as WebGPURenderPass;
|
|
78
|
+
|
|
79
|
+
// Set pipeline
|
|
80
|
+
webgpuRenderPass.handle.setPipeline(this.handle);
|
|
81
|
+
|
|
82
|
+
// Set bindings (uniform buffers, textures etc)
|
|
83
|
+
const bindGroup = this._getBindGroup();
|
|
84
|
+
if (bindGroup) {
|
|
85
|
+
webgpuRenderPass.handle.setBindGroup(0, bindGroup);
|
|
77
86
|
}
|
|
78
|
-
// for (let i = 0; i < this._bufferSlots.length; ++i) {
|
|
79
|
-
// const bufferName = this._bufferSlots[i];
|
|
80
|
-
// if (attributes[bufferName]) {
|
|
81
|
-
// this.handle
|
|
82
|
-
// }
|
|
83
|
-
// }
|
|
84
|
-
}
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
// Set attributes
|
|
89
|
+
// Note: Rebinds constant attributes before each draw call
|
|
90
|
+
options.vertexArray.bindBeforeRender(options.renderPass);
|
|
91
|
+
|
|
92
|
+
// Draw
|
|
93
|
+
if (options.indexCount) {
|
|
94
|
+
webgpuRenderPass.handle.drawIndexed(
|
|
95
|
+
options.indexCount,
|
|
96
|
+
options.instanceCount,
|
|
97
|
+
options.firstIndex,
|
|
98
|
+
options.baseVertex,
|
|
99
|
+
options.firstInstance
|
|
100
|
+
);
|
|
101
|
+
} else {
|
|
102
|
+
webgpuRenderPass.handle.draw(
|
|
103
|
+
options.vertexCount || 0,
|
|
104
|
+
options.instanceCount || 1, // If 0, nothing will be drawn
|
|
105
|
+
options.firstInstance
|
|
96
106
|
);
|
|
97
107
|
}
|
|
98
|
-
}
|
|
99
108
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
throw new Error('WebGPU does not support uniforms');
|
|
103
|
-
}
|
|
104
|
-
}
|
|
109
|
+
// Note: Rebinds constant attributes before each draw call
|
|
110
|
+
options.vertexArray.unbindAfterRender(options.renderPass);
|
|
105
111
|
|
|
106
|
-
|
|
107
|
-
return this._buffers;
|
|
112
|
+
return true;
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
/** Return a bind group created by setBindings */
|
|
111
116
|
_getBindGroup() {
|
|
112
|
-
|
|
117
|
+
if (this.props.shaderLayout.bindings.length === 0) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
|
|
122
|
+
this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
|
|
123
|
+
|
|
124
|
+
// Set up the bindings
|
|
125
|
+
// TODO what if bindings change? We need to rebuild the bind group!
|
|
126
|
+
this._bindGroup =
|
|
127
|
+
this._bindGroup ||
|
|
128
|
+
getBindGroup(
|
|
129
|
+
this.device.handle,
|
|
130
|
+
this._bindGroupLayout,
|
|
131
|
+
this.props.shaderLayout,
|
|
132
|
+
this._bindings
|
|
133
|
+
);
|
|
134
|
+
|
|
113
135
|
return this._bindGroup;
|
|
114
136
|
}
|
|
115
137
|
|
|
116
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Populate the complex WebGPU GPURenderPipelineDescriptor
|
|
140
|
+
*/
|
|
117
141
|
protected _getRenderPipelineDescriptor() {
|
|
118
142
|
// Set up the vertex stage
|
|
119
143
|
const vertex: GPUVertexState = {
|
|
120
144
|
module: cast<WebGPUShader>(this.props.vs).handle,
|
|
121
|
-
entryPoint: this.props.
|
|
122
|
-
buffers: getVertexBufferLayout(this.props.
|
|
145
|
+
entryPoint: this.props.vertexEntryPoint || 'main',
|
|
146
|
+
buffers: getVertexBufferLayout(this.props.shaderLayout, this.props.bufferLayout)
|
|
123
147
|
};
|
|
124
148
|
|
|
125
149
|
// Set up the fragment stage
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
]
|
|
137
|
-
};
|
|
138
|
-
}
|
|
150
|
+
const fragment: GPUFragmentState = {
|
|
151
|
+
module: cast<WebGPUShader>(this.props.fs).handle,
|
|
152
|
+
entryPoint: this.props.fragmentEntryPoint || 'main',
|
|
153
|
+
targets: [
|
|
154
|
+
{
|
|
155
|
+
// TODO exclamation mark hack!
|
|
156
|
+
format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
};
|
|
139
160
|
|
|
140
161
|
// WebGPU has more restrictive topology support than WebGL
|
|
141
162
|
switch (this.props.topology) {
|
|
142
|
-
case 'triangle-fan':
|
|
143
|
-
case 'line-loop':
|
|
163
|
+
case 'triangle-fan-webgl':
|
|
164
|
+
case 'line-loop-webgl':
|
|
144
165
|
throw new Error(`WebGPU does not support primitive topology ${this.props.topology}`);
|
|
145
166
|
default:
|
|
146
167
|
}
|
|
147
168
|
|
|
148
169
|
// Create a partially populated descriptor
|
|
149
|
-
|
|
170
|
+
const descriptor: GPURenderPipelineDescriptor = {
|
|
150
171
|
vertex,
|
|
151
172
|
fragment,
|
|
152
173
|
primitive: {
|
|
153
174
|
topology: this.props.topology
|
|
154
|
-
}
|
|
175
|
+
},
|
|
176
|
+
layout: 'auto'
|
|
155
177
|
};
|
|
156
178
|
|
|
157
179
|
// Set parameters on the descriptor
|
|
@@ -159,88 +181,46 @@ export default class WebGPURenderPipeline extends RenderPipeline {
|
|
|
159
181
|
|
|
160
182
|
return descriptor;
|
|
161
183
|
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
_setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
|
|
187
|
+
if (this._indexBuffer) {
|
|
188
|
+
webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
|
|
189
|
+
}
|
|
162
190
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
firstIndex?: number;
|
|
170
|
-
firstInstance?: number;
|
|
171
|
-
baseVertex?: number;
|
|
172
|
-
}): void {
|
|
173
|
-
const webgpuRenderPass =
|
|
174
|
-
cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
|
|
175
|
-
|
|
176
|
-
// Set pipeline
|
|
177
|
-
webgpuRenderPass.handle.setPipeline(this.handle);
|
|
178
|
-
|
|
179
|
-
// Set bindings (uniform buffers, textures etc)
|
|
180
|
-
if (this._getBindGroup()) {
|
|
181
|
-
webgpuRenderPass.handle.setBindGroup(0, this._getBindGroup());
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Set attributes
|
|
185
|
-
this._setAttributeBuffers(webgpuRenderPass);
|
|
186
|
-
|
|
187
|
-
// Draw
|
|
188
|
-
if (options.indexCount) {
|
|
189
|
-
webgpuRenderPass.handle.drawIndexed(
|
|
190
|
-
options.indexCount,
|
|
191
|
-
options.instanceCount,
|
|
192
|
-
options.firstIndex,
|
|
193
|
-
options.baseVertex,
|
|
194
|
-
options.firstInstance
|
|
191
|
+
const buffers = this._getBuffers();
|
|
192
|
+
for (let i = 0; i < buffers.length; ++i) {
|
|
193
|
+
const buffer = cast<WebGPUBuffer>(buffers[i]);
|
|
194
|
+
if (!buffer) {
|
|
195
|
+
const attribute = this.props.shaderLayout.attributes.find(
|
|
196
|
+
(attribute) => attribute.location === i
|
|
195
197
|
);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
options.vertexCount || 0,
|
|
199
|
-
options.instanceCount,
|
|
200
|
-
options.firstIndex,
|
|
201
|
-
options.firstInstance
|
|
198
|
+
throw new Error(
|
|
199
|
+
`No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
|
|
202
200
|
);
|
|
203
201
|
}
|
|
202
|
+
webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
|
|
204
203
|
}
|
|
205
204
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
// TODO - HANDLE buffer maps
|
|
206
|
+
/*
|
|
207
|
+
for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
|
|
208
|
+
const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
|
|
209
|
+
if (!buffer) {
|
|
210
|
+
log.warn(`Missing buffer for buffer map ${bufferName}`)();
|
|
211
|
+
continue;
|
|
209
212
|
}
|
|
210
213
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
(attribute) => attribute.location === i
|
|
217
|
-
);
|
|
218
|
-
throw new Error(
|
|
219
|
-
`No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// TODO - HANDLE buffer maps
|
|
226
|
-
/*
|
|
227
|
-
for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferMap)) {
|
|
228
|
-
const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
|
|
229
|
-
if (!buffer) {
|
|
230
|
-
log.warn(`Missing buffer for buffer map ${bufferName}`)();
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if ('location' in attributeMapping) {
|
|
214
|
+
if ('location' in attributeMapping) {
|
|
215
|
+
// @ts-expect-error TODO model must not depend on webgpu
|
|
216
|
+
renderPass.handle.setVertexBuffer(layout.location, buffer.handle);
|
|
217
|
+
} else {
|
|
218
|
+
for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
|
|
235
219
|
// @ts-expect-error TODO model must not depend on webgpu
|
|
236
|
-
renderPass.handle.setVertexBuffer(
|
|
237
|
-
} else {
|
|
238
|
-
for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
|
|
239
|
-
// @ts-expect-error TODO model must not depend on webgpu
|
|
240
|
-
renderPass.handle.setVertexBuffer(field.location, buffer.handle);
|
|
241
|
-
}
|
|
220
|
+
renderPass.handle.setVertexBuffer(field.location, buffer.handle);
|
|
242
221
|
}
|
|
243
222
|
}
|
|
244
|
-
*/
|
|
245
223
|
}
|
|
224
|
+
*
|
|
246
225
|
}
|
|
226
|
+
*/
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {Sampler, SamplerProps} from '@luma.gl/
|
|
2
|
-
import type WebGPUDevice from '../webgpu-device';
|
|
1
|
+
import {Sampler, SamplerProps} from '@luma.gl/core';
|
|
2
|
+
import type {WebGPUDevice} from '../webgpu-device';
|
|
3
3
|
|
|
4
4
|
export type WebGPUSamplerProps = SamplerProps & {
|
|
5
5
|
handle?: GPUSampler;
|
|
6
|
-
}
|
|
6
|
+
};
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
*
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
11
|
+
export class WebGPUSampler extends Sampler {
|
|
12
12
|
readonly device: WebGPUDevice;
|
|
13
13
|
readonly handle: GPUSampler;
|
|
14
14
|
|
|
@@ -17,16 +17,19 @@ export default class WebGPUSampler extends Sampler {
|
|
|
17
17
|
this.device = device;
|
|
18
18
|
|
|
19
19
|
// Prepare sampler props
|
|
20
|
-
const samplerProps = this.props;
|
|
20
|
+
const samplerProps: Partial<WebGPUSamplerProps> = {...this.props};
|
|
21
21
|
if (samplerProps.type !== 'comparison-sampler') {
|
|
22
22
|
delete samplerProps.compare;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
this.handle = this.handle || this.device.handle.createSampler(
|
|
25
|
+
this.handle = this.handle || this.device.handle.createSampler(samplerProps);
|
|
26
26
|
this.handle.label = this.props.id;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
destroy(): void {
|
|
29
|
+
override destroy(): void {
|
|
30
|
+
// GPUSampler does not have a destroy method
|
|
30
31
|
// this.handle.destroy();
|
|
32
|
+
// @ts-expect-error readonly
|
|
33
|
+
this.handle = null;
|
|
31
34
|
}
|
|
32
35
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
5
|
+
import type {ShaderProps, CompilerMessage} from '@luma.gl/core';
|
|
6
|
+
import {Shader, log} from '@luma.gl/core';
|
|
7
|
+
import type {WebGPUDevice} from '../webgpu-device';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Immutable shader
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
12
|
+
export class WebGPUShader extends Shader {
|
|
13
13
|
readonly device: WebGPUDevice;
|
|
14
14
|
readonly handle: GPUShaderModule;
|
|
15
15
|
|
|
16
|
-
constructor(device: WebGPUDevice, props:
|
|
16
|
+
constructor(device: WebGPUDevice, props: ShaderProps) {
|
|
17
17
|
super(device, props);
|
|
18
18
|
this.device = device;
|
|
19
19
|
|
|
@@ -25,10 +25,13 @@ export default class WebGPUShader extends Shader {
|
|
|
25
25
|
this._checkCompilationError(this.device.handle.popErrorScope());
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
async _checkCompilationError(errorScope: Promise<GPUError>): Promise<void> {
|
|
29
|
-
const error = await errorScope as GPUValidationError;
|
|
28
|
+
async _checkCompilationError(errorScope: Promise<GPUError | null>): Promise<void> {
|
|
29
|
+
const error = (await errorScope) as GPUValidationError;
|
|
30
30
|
if (error) {
|
|
31
|
-
|
|
31
|
+
// The `Shader` base class will determine if debug window should be opened based on props
|
|
32
|
+
this.debugShader();
|
|
33
|
+
|
|
34
|
+
const shaderLog = await this.getCompilationInfo();
|
|
32
35
|
log.error(`Shader compilation error: ${error.message}`, shaderLog)();
|
|
33
36
|
// Note: Even though this error is asynchronous and thrown after the constructor completes,
|
|
34
37
|
// it will result in a useful stack trace leading back to the constructor
|
|
@@ -36,37 +39,29 @@ export default class WebGPUShader extends Shader {
|
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
destroy() {
|
|
42
|
+
override destroy(): void {
|
|
43
|
+
// Note: WebGPU does not offer a method to destroy shaders
|
|
40
44
|
// this.handle.destroy();
|
|
45
|
+
// @ts-expect-error readonly
|
|
46
|
+
this.handle = null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Returns compilation info for this shader */
|
|
50
|
+
async getCompilationInfo(): Promise<readonly CompilerMessage[]> {
|
|
51
|
+
const compilationInfo = await this.handle.getCompilationInfo();
|
|
52
|
+
return compilationInfo.messages;
|
|
41
53
|
}
|
|
42
54
|
|
|
55
|
+
// PRIVATE METHODS
|
|
56
|
+
|
|
43
57
|
protected createHandle(): GPUShaderModule {
|
|
44
58
|
const {source} = this.props;
|
|
45
59
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// wgsl uses C++ "auto" style arrow notation
|
|
50
|
-
language = source.includes('->') ? 'wgsl' : 'glsl';
|
|
60
|
+
const isGLSL = source.includes('#version');
|
|
61
|
+
if (this.props.language === 'glsl' || isGLSL) {
|
|
62
|
+
throw new Error('GLSL shaders are not supported in WebGPU');
|
|
51
63
|
}
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
case 'wgsl':
|
|
55
|
-
return this.device.handle.createShaderModule({code: source});
|
|
56
|
-
case 'glsl':
|
|
57
|
-
return this.device.handle.createShaderModule({
|
|
58
|
-
code: source,
|
|
59
|
-
// @ts-expect-error
|
|
60
|
-
transform: (glsl) => this.device.glslang.compileGLSL(glsl, type)
|
|
61
|
-
});
|
|
62
|
-
default:
|
|
63
|
-
throw new Error(language);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Returns compilation info for this shader */
|
|
68
|
-
async compilationInfo(): Promise<readonly CompilerMessage[]> {
|
|
69
|
-
const compilationInfo = await this.handle.compilationInfo();
|
|
70
|
-
return compilationInfo.messages;
|
|
65
|
+
return this.device.handle.createShaderModule({code: source});
|
|
71
66
|
}
|
|
72
67
|
}
|