@luma.gl/webgpu 9.0.0-beta.1 → 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/dist/adapter/helpers/accessor-to-format.js +102 -1
- package/dist/adapter/helpers/convert-texture-format.d.ts.map +1 -1
- package/dist/adapter/helpers/convert-texture-format.js +8 -5
- package/dist/adapter/helpers/get-bind-group.d.ts +3 -3
- package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
- package/dist/adapter/helpers/get-bind-group.js +57 -41
- package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
- package/dist/adapter/helpers/get-vertex-buffer-layout.js +117 -80
- package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -1
- package/dist/adapter/helpers/webgpu-parameters.js +185 -125
- package/dist/adapter/resources/webgpu-buffer.d.ts +1 -1
- package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-buffer.js +119 -62
- package/dist/adapter/resources/webgpu-command-encoder.d.ts +7 -1
- package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-command-encoder.js +81 -49
- package/dist/adapter/resources/webgpu-compute-pass.d.ts +15 -9
- package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pass.js +76 -41
- package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +14 -4
- package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pipeline.js +46 -19
- package/dist/adapter/resources/webgpu-external-texture.d.ts +2 -2
- package/dist/adapter/resources/webgpu-external-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-external-texture.js +35 -18
- package/dist/adapter/resources/webgpu-framebuffer.d.ts +1 -1
- package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-framebuffer.js +14 -7
- 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 +4 -2
- package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pass.js +133 -105
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts +52 -5
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pipeline.js +151 -78
- package/dist/adapter/resources/webgpu-sampler.d.ts +1 -1
- package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-sampler.js +21 -15
- package/dist/adapter/resources/webgpu-shader.d.ts +2 -5
- package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-shader.js +45 -44
- 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 +8 -8
- package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-texture.js +130 -107
- package/dist/adapter/resources/webgpu-vertex-array.d.ts +9 -8
- package/dist/adapter/resources/webgpu-vertex-array.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-vertex-array.js +60 -39
- package/dist/adapter/webgpu-canvas-context.d.ts +3 -3
- package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
- package/dist/adapter/webgpu-canvas-context.js +101 -67
- package/dist/adapter/webgpu-device.d.ts +26 -28
- package/dist/adapter/webgpu-device.d.ts.map +1 -1
- package/dist/adapter/webgpu-device.js +254 -220
- package/dist/dist.dev.js +804 -2270
- package/dist/dist.min.js +9 -0
- package/dist/index.cjs +366 -485
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist.min.js +1 -22
- package/package.json +9 -7
- package/src/adapter/helpers/accessor-to-format.ts +5 -1
- package/src/adapter/helpers/convert-texture-format.ts +4 -1
- package/src/adapter/helpers/get-bind-group.ts +12 -6
- package/src/adapter/helpers/get-vertex-buffer-layout.ts +13 -5
- package/src/adapter/helpers/webgpu-parameters.ts +79 -15
- package/src/adapter/resources/webgpu-buffer.ts +24 -11
- package/src/adapter/resources/webgpu-command-encoder.ts +24 -9
- package/src/adapter/resources/webgpu-compute-pass.ts +45 -22
- package/src/adapter/resources/webgpu-compute-pipeline.ts +48 -16
- package/src/adapter/resources/webgpu-external-texture.ts +14 -6
- package/src/adapter/resources/webgpu-framebuffer.ts +4 -0
- package/src/adapter/resources/webgpu-query-set.ts +37 -0
- package/src/adapter/resources/webgpu-render-pass.ts +37 -14
- package/src/adapter/resources/webgpu-render-pipeline.ts +80 -119
- package/src/adapter/resources/webgpu-sampler.ts +4 -1
- package/src/adapter/resources/webgpu-shader.ts +14 -25
- package/src/adapter/resources/webgpu-texture-view.ts +46 -0
- package/src/adapter/resources/webgpu-texture.ts +33 -28
- package/src/adapter/resources/webgpu-vertex-array.ts +28 -20
- package/src/adapter/webgpu-canvas-context.ts +10 -4
- package/src/adapter/webgpu-device.ts +109 -106
- package/src/index.ts +2 -1
- 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 -100
- 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/resources/webgpu-vertex-array.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/glsl/glsllang.d.ts +0 -3
- package/dist/glsl/glsllang.d.ts.map +0 -1
- package/dist/glsl/glsllang.js +0 -9
- package/dist/glsl/glsllang.js.map +0 -1
- package/dist/index.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/glsl/glsllang.ts +0 -14
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
1
5
|
import type {RenderPassProps, RenderPassParameters, Binding, Framebuffer} from '@luma.gl/core';
|
|
2
6
|
import {Buffer, RenderPass, RenderPipeline, cast, log} from '@luma.gl/core';
|
|
3
7
|
import {WebGPUDevice} from '../webgpu-device';
|
|
4
8
|
import {WebGPUBuffer} from './webgpu-buffer';
|
|
5
|
-
import {
|
|
9
|
+
import {WebGPUTextureView} from './webgpu-texture-view';
|
|
6
10
|
// import {WebGPUCommandEncoder} from './webgpu-command-encoder';
|
|
7
11
|
import {WebGPURenderPipeline} from './webgpu-render-pipeline';
|
|
12
|
+
import {WebGPUQuerySet} from './webgpu-query-set';
|
|
8
13
|
|
|
9
14
|
export class WebGPURenderPass extends RenderPass {
|
|
10
15
|
readonly device: WebGPUDevice;
|
|
@@ -16,13 +21,30 @@ export class WebGPURenderPass extends RenderPass {
|
|
|
16
21
|
constructor(device: WebGPUDevice, props: RenderPassProps = {}) {
|
|
17
22
|
super(device, props);
|
|
18
23
|
this.device = device;
|
|
19
|
-
const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer()
|
|
24
|
+
const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer();
|
|
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
|
+
|
|
43
|
+
this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
|
|
44
|
+
this.handle.label = this.props.id;
|
|
21
45
|
log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
|
|
22
46
|
log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
|
|
23
47
|
log.groupEnd(3)();
|
|
24
|
-
this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
|
|
25
|
-
this.handle.label = this.props.id;
|
|
26
48
|
}
|
|
27
49
|
|
|
28
50
|
override destroy(): void {}
|
|
@@ -124,19 +146,20 @@ export class WebGPURenderPass extends RenderPass {
|
|
|
124
146
|
this.handle.insertDebugMarker(markerLabel);
|
|
125
147
|
}
|
|
126
148
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
149
|
+
beginOcclusionQuery(queryIndex: number): void {
|
|
150
|
+
this.handle.beginOcclusionQuery(queryIndex);
|
|
151
|
+
}
|
|
152
|
+
endOcclusionQuery(): void {
|
|
153
|
+
this.handle.endOcclusionQuery();
|
|
154
|
+
}
|
|
132
155
|
|
|
133
156
|
// executeBundles(bundles: Iterable<GPURenderBundle>): void;
|
|
134
157
|
|
|
135
158
|
// INTERNAL
|
|
136
159
|
|
|
137
|
-
/**
|
|
160
|
+
/**
|
|
138
161
|
* Partial render pass descriptor. Used by WebGPURenderPass.
|
|
139
|
-
* @returns attachments fields of a renderpass descriptor.
|
|
162
|
+
* @returns attachments fields of a renderpass descriptor.
|
|
140
163
|
*/
|
|
141
164
|
protected getRenderPassDescriptor(framebuffer: Framebuffer): GPURenderPassDescriptor {
|
|
142
165
|
const renderPassDescriptor: GPURenderPassDescriptor = {
|
|
@@ -147,14 +170,14 @@ export class WebGPURenderPass extends RenderPass {
|
|
|
147
170
|
// clear values
|
|
148
171
|
loadOp: this.props.clearColor !== false ? 'clear' : 'load',
|
|
149
172
|
colorClearValue: this.props.clearColor || [0, 0, 0, 0],
|
|
150
|
-
storeOp: this.props.discard? 'discard': 'store',
|
|
173
|
+
storeOp: this.props.discard ? 'discard' : 'store',
|
|
151
174
|
// ...colorAttachment,
|
|
152
|
-
view: (colorAttachment as
|
|
175
|
+
view: (colorAttachment as WebGPUTextureView).handle
|
|
153
176
|
}));
|
|
154
177
|
|
|
155
178
|
if (framebuffer.depthStencilAttachment) {
|
|
156
179
|
renderPassDescriptor.depthStencilAttachment = {
|
|
157
|
-
view: (framebuffer.depthStencilAttachment as
|
|
180
|
+
view: (framebuffer.depthStencilAttachment as WebGPUTextureView).handle
|
|
158
181
|
};
|
|
159
182
|
const {depthStencilAttachment} = renderPassDescriptor;
|
|
160
183
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// luma.gl MIT license
|
|
2
2
|
|
|
3
|
-
import type {Binding,
|
|
4
|
-
import {RenderPipeline, RenderPipelineProps, cast, log
|
|
3
|
+
import type {Binding, RenderPass, VertexArray} from '@luma.gl/core';
|
|
4
|
+
import {RenderPipeline, RenderPipelineProps, cast, log} from '@luma.gl/core';
|
|
5
5
|
import {applyParametersToRenderPipelineDescriptor} from '../helpers/webgpu-parameters';
|
|
6
6
|
import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
|
|
7
7
|
import {getBindGroup} from '../helpers/get-bind-group';
|
|
@@ -25,12 +25,8 @@ export class WebGPURenderPipeline extends RenderPipeline {
|
|
|
25
25
|
vs: WebGPUShader;
|
|
26
26
|
fs: WebGPUShader | null = null;
|
|
27
27
|
|
|
28
|
-
// private _bufferSlots: Record<string, number>;
|
|
29
|
-
// private _buffers: Buffer[];
|
|
30
|
-
// private _firstIndex: number;
|
|
31
|
-
// private _lastIndex: number;
|
|
32
|
-
|
|
33
28
|
/** For internal use to create BindGroups */
|
|
29
|
+
private _bindings: Record<string, Binding>;
|
|
34
30
|
private _bindGroupLayout: GPUBindGroupLayout | null = null;
|
|
35
31
|
private _bindGroup: GPUBindGroup | null = null;
|
|
36
32
|
|
|
@@ -43,74 +39,30 @@ export class WebGPURenderPipeline extends RenderPipeline {
|
|
|
43
39
|
log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
|
|
44
40
|
log.probe(1, JSON.stringify(descriptor, null, 2))();
|
|
45
41
|
log.groupEnd(1)();
|
|
46
|
-
this.handle = this.device.handle.createRenderPipeline(descriptor);
|
|
42
|
+
this.handle = this.device.handle.createRenderPipeline(descriptor);
|
|
47
43
|
}
|
|
48
44
|
this.handle.label = this.props.id;
|
|
49
45
|
|
|
50
46
|
this.vs = cast<WebGPUShader>(props.vs);
|
|
51
47
|
this.fs = cast<WebGPUShader>(props.fs);
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
// this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
|
|
49
|
+
this._bindings = {...this.props.bindings};
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
override destroy(): void {
|
|
58
53
|
// WebGPURenderPipeline has no destroy method.
|
|
54
|
+
this.handle = null;
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/*
|
|
66
|
-
setAttributes(attributes: Record<string, Buffer>): void {
|
|
67
|
-
for (const [name, buffer] of Object.entries(attributes)) {
|
|
68
|
-
const bufferIndex = this._bufferSlots[name];
|
|
69
|
-
if (bufferIndex >= 0) {
|
|
70
|
-
this._buffers[bufferIndex] = buffer;
|
|
71
|
-
} else {
|
|
72
|
-
throw new Error(
|
|
73
|
-
`Setting attribute '${name}' not listed in shader layout for program ${this.id}`
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// for (let i = 0; i < this._bufferSlots.length; ++i) {
|
|
78
|
-
// const bufferName = this._bufferSlots[i];
|
|
79
|
-
// if (attributes[bufferName]) {
|
|
80
|
-
// this.handle
|
|
81
|
-
// }
|
|
82
|
-
// }
|
|
83
|
-
}
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
// setConstantAttributes(attributes: Record<string, TypedArray>): void {
|
|
87
|
-
// throw new Error('not implemented');
|
|
88
|
-
// }
|
|
89
|
-
|
|
57
|
+
/**
|
|
58
|
+
* @todo Use renderpass.setBindings() ?
|
|
59
|
+
* @todo Do we want to expose BindGroups in the API and remove this?
|
|
60
|
+
*/
|
|
90
61
|
setBindings(bindings: Record<string, Binding>): void {
|
|
91
|
-
|
|
92
|
-
// Do we want to save things on CPU side?
|
|
93
|
-
Object.assign(this.props.bindings, bindings);
|
|
94
|
-
|
|
95
|
-
// Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
|
|
96
|
-
this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
|
|
97
|
-
|
|
98
|
-
// Set up the bindings
|
|
99
|
-
this._bindGroup = getBindGroup(
|
|
100
|
-
this.device.handle,
|
|
101
|
-
this._bindGroupLayout,
|
|
102
|
-
this.props.shaderLayout,
|
|
103
|
-
this.props.bindings
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
setUniforms(uniforms: Record<string, UniformValue>): void {
|
|
109
|
-
if (!isObjectEmpty(uniforms)) {
|
|
110
|
-
throw new Error('WebGPU does not support uniforms');
|
|
111
|
-
}
|
|
62
|
+
Object.assign(this._bindings, bindings);
|
|
112
63
|
}
|
|
113
64
|
|
|
65
|
+
/** @todo - should this be moved to renderpass? */
|
|
114
66
|
draw(options: {
|
|
115
67
|
renderPass: RenderPass;
|
|
116
68
|
vertexArray: VertexArray;
|
|
@@ -121,9 +73,8 @@ export class WebGPURenderPipeline extends RenderPipeline {
|
|
|
121
73
|
firstIndex?: number;
|
|
122
74
|
firstInstance?: number;
|
|
123
75
|
baseVertex?: number;
|
|
124
|
-
}):
|
|
125
|
-
const webgpuRenderPass
|
|
126
|
-
cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
|
|
76
|
+
}): boolean {
|
|
77
|
+
const webgpuRenderPass = options.renderPass as WebGPURenderPass;
|
|
127
78
|
|
|
128
79
|
// Set pipeline
|
|
129
80
|
webgpuRenderPass.handle.setPipeline(this.handle);
|
|
@@ -134,7 +85,6 @@ export class WebGPURenderPipeline extends RenderPipeline {
|
|
|
134
85
|
webgpuRenderPass.handle.setBindGroup(0, bindGroup);
|
|
135
86
|
}
|
|
136
87
|
|
|
137
|
-
|
|
138
88
|
// Set attributes
|
|
139
89
|
// Note: Rebinds constant attributes before each draw call
|
|
140
90
|
options.vertexArray.bindBeforeRender(options.renderPass);
|
|
@@ -158,43 +108,55 @@ export class WebGPURenderPipeline extends RenderPipeline {
|
|
|
158
108
|
|
|
159
109
|
// Note: Rebinds constant attributes before each draw call
|
|
160
110
|
options.vertexArray.unbindAfterRender(options.renderPass);
|
|
161
|
-
}
|
|
162
111
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// }
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
166
114
|
|
|
167
115
|
/** Return a bind group created by setBindings */
|
|
168
116
|
_getBindGroup() {
|
|
169
|
-
|
|
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
|
+
|
|
170
135
|
return this._bindGroup;
|
|
171
136
|
}
|
|
172
137
|
|
|
173
|
-
/**
|
|
174
|
-
* Populate the complex WebGPU GPURenderPipelineDescriptor
|
|
138
|
+
/**
|
|
139
|
+
* Populate the complex WebGPU GPURenderPipelineDescriptor
|
|
175
140
|
*/
|
|
176
141
|
protected _getRenderPipelineDescriptor() {
|
|
177
142
|
// Set up the vertex stage
|
|
178
143
|
const vertex: GPUVertexState = {
|
|
179
144
|
module: cast<WebGPUShader>(this.props.vs).handle,
|
|
180
|
-
entryPoint: this.props.
|
|
145
|
+
entryPoint: this.props.vertexEntryPoint || 'main',
|
|
181
146
|
buffers: getVertexBufferLayout(this.props.shaderLayout, this.props.bufferLayout)
|
|
182
147
|
};
|
|
183
148
|
|
|
184
149
|
// Set up the fragment stage
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
]
|
|
196
|
-
};
|
|
197
|
-
}
|
|
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
|
+
};
|
|
198
160
|
|
|
199
161
|
// WebGPU has more restrictive topology support than WebGL
|
|
200
162
|
switch (this.props.topology) {
|
|
@@ -219,47 +181,46 @@ export class WebGPURenderPipeline extends RenderPipeline {
|
|
|
219
181
|
|
|
220
182
|
return descriptor;
|
|
221
183
|
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
_setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
|
|
187
|
+
if (this._indexBuffer) {
|
|
188
|
+
webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
|
|
189
|
+
}
|
|
222
190
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
|
197
|
+
);
|
|
198
|
+
throw new Error(
|
|
199
|
+
`No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
|
|
200
|
+
);
|
|
227
201
|
}
|
|
202
|
+
webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
|
|
203
|
+
}
|
|
228
204
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
throw new Error(
|
|
237
|
-
`No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
|
|
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;
|
|
241
212
|
}
|
|
242
213
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
log.warn(`Missing buffer for buffer map ${bufferName}`)();
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
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)) {
|
|
253
219
|
// @ts-expect-error TODO model must not depend on webgpu
|
|
254
|
-
renderPass.handle.setVertexBuffer(
|
|
255
|
-
} else {
|
|
256
|
-
for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
|
|
257
|
-
// @ts-expect-error TODO model must not depend on webgpu
|
|
258
|
-
renderPass.handle.setVertexBuffer(field.location, buffer.handle);
|
|
259
|
-
}
|
|
220
|
+
renderPass.handle.setVertexBuffer(field.location, buffer.handle);
|
|
260
221
|
}
|
|
261
222
|
}
|
|
262
|
-
*
|
|
263
223
|
}
|
|
264
|
-
|
|
224
|
+
*
|
|
265
225
|
}
|
|
226
|
+
*/
|
|
@@ -3,7 +3,7 @@ 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
|
*
|
|
@@ -27,6 +27,9 @@ export class WebGPUSampler extends Sampler {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
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,14 +1,11 @@
|
|
|
1
|
-
// luma.gl
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
2
3
|
// Copyright (c) vis.gl contributors
|
|
3
4
|
|
|
4
5
|
import type {ShaderProps, CompilerMessage} from '@luma.gl/core';
|
|
5
6
|
import {Shader, log} from '@luma.gl/core';
|
|
6
7
|
import type {WebGPUDevice} from '../webgpu-device';
|
|
7
8
|
|
|
8
|
-
export type WebGPUShaderProps = ShaderProps & {
|
|
9
|
-
handle?: GPUShaderModule;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* Immutable shader
|
|
14
11
|
*/
|
|
@@ -16,7 +13,7 @@ export class WebGPUShader extends Shader {
|
|
|
16
13
|
readonly device: WebGPUDevice;
|
|
17
14
|
readonly handle: GPUShaderModule;
|
|
18
15
|
|
|
19
|
-
constructor(device: WebGPUDevice, props:
|
|
16
|
+
constructor(device: WebGPUDevice, props: ShaderProps) {
|
|
20
17
|
super(device, props);
|
|
21
18
|
this.device = device;
|
|
22
19
|
|
|
@@ -29,8 +26,11 @@ export class WebGPUShader extends Shader {
|
|
|
29
26
|
}
|
|
30
27
|
|
|
31
28
|
async _checkCompilationError(errorScope: Promise<GPUError | null>): Promise<void> {
|
|
32
|
-
const error = await errorScope as GPUValidationError;
|
|
29
|
+
const error = (await errorScope) as GPUValidationError;
|
|
33
30
|
if (error) {
|
|
31
|
+
// The `Shader` base class will determine if debug window should be opened based on props
|
|
32
|
+
this.debugShader();
|
|
33
|
+
|
|
34
34
|
const shaderLog = await this.getCompilationInfo();
|
|
35
35
|
log.error(`Shader compilation error: ${error.message}`, shaderLog)();
|
|
36
36
|
// Note: Even though this error is asynchronous and thrown after the constructor completes,
|
|
@@ -42,6 +42,8 @@ export class WebGPUShader extends Shader {
|
|
|
42
42
|
override destroy(): void {
|
|
43
43
|
// Note: WebGPU does not offer a method to destroy shaders
|
|
44
44
|
// this.handle.destroy();
|
|
45
|
+
// @ts-expect-error readonly
|
|
46
|
+
this.handle = null;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
/** Returns compilation info for this shader */
|
|
@@ -53,26 +55,13 @@ export class WebGPUShader extends Shader {
|
|
|
53
55
|
// PRIVATE METHODS
|
|
54
56
|
|
|
55
57
|
protected createHandle(): GPUShaderModule {
|
|
56
|
-
const {source
|
|
58
|
+
const {source} = this.props;
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// wgsl uses C++ "auto" style arrow notation
|
|
62
|
-
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');
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
case 'wgsl':
|
|
67
|
-
return this.device.handle.createShaderModule({code: source});
|
|
68
|
-
case 'glsl':
|
|
69
|
-
return this.device.handle.createShaderModule({
|
|
70
|
-
code: source,
|
|
71
|
-
// @ts-expect-error
|
|
72
|
-
transform: (glsl) => this.device.glslang.compileGLSL(glsl, stage)
|
|
73
|
-
});
|
|
74
|
-
default:
|
|
75
|
-
throw new Error(language);
|
|
76
|
-
}
|
|
65
|
+
return this.device.handle.createShaderModule({code: source});
|
|
77
66
|
}
|
|
78
67
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {TextureView, TextureViewProps} from '@luma.gl/core';
|
|
6
|
+
import type {WebGPUDevice} from '../webgpu-device';
|
|
7
|
+
import type {WebGPUTexture} from './webgpu-texture';
|
|
8
|
+
|
|
9
|
+
export type WebGPUTextureViewProps = TextureViewProps & {
|
|
10
|
+
handle?: GPUTextureView;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export class WebGPUTextureView extends TextureView {
|
|
17
|
+
readonly device: WebGPUDevice;
|
|
18
|
+
readonly handle: GPUTextureView;
|
|
19
|
+
readonly texture: WebGPUTexture;
|
|
20
|
+
|
|
21
|
+
constructor(device: WebGPUDevice, props: WebGPUTextureViewProps & {texture: WebGPUTexture}) {
|
|
22
|
+
super(device, props);
|
|
23
|
+
this.device = device;
|
|
24
|
+
this.texture = props.texture;
|
|
25
|
+
|
|
26
|
+
this.handle =
|
|
27
|
+
this.handle ||
|
|
28
|
+
this.texture.handle.createView({
|
|
29
|
+
format: (props.format || this.texture.format) as GPUTextureFormat,
|
|
30
|
+
dimension: props.dimension || this.texture.dimension,
|
|
31
|
+
aspect: props.aspect,
|
|
32
|
+
baseMipLevel: props.baseMipLevel,
|
|
33
|
+
mipLevelCount: props.mipLevelCount, // GPUIntegerCoordinate;
|
|
34
|
+
baseArrayLayer: props.baseArrayLayer, // GPUIntegerCoordinate;
|
|
35
|
+
arrayLayerCount: props.arrayLayerCount // GPUIntegerCoordinate;
|
|
36
|
+
});
|
|
37
|
+
this.handle.label = this.props.id;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override destroy(): void {
|
|
41
|
+
// GPUTextureView does not have a destroy method
|
|
42
|
+
// this.handle.destroy();
|
|
43
|
+
// @ts-expect-error readonly
|
|
44
|
+
this.handle = null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
// luma.gl
|
|
2
|
-
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Texture, TextureProps, TextureViewProps, Sampler, SamplerProps} from '@luma.gl/core';
|
|
3
6
|
import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
|
|
4
7
|
import type {WebGPUDevice} from '../webgpu-device';
|
|
5
8
|
import {WebGPUSampler} from './webgpu-sampler';
|
|
9
|
+
import {WebGPUTextureView} from './webgpu-texture-view';
|
|
6
10
|
|
|
7
11
|
const BASE_DIMENSIONS: Record<string, '1d' | '2d' | '3d'> = {
|
|
8
12
|
'1d': '1d',
|
|
9
13
|
'2d': '2d',
|
|
10
14
|
'2d-array': '2d',
|
|
11
|
-
|
|
15
|
+
cube: '2d',
|
|
12
16
|
'cube-array': '2d',
|
|
13
17
|
'3d': '3d'
|
|
14
18
|
};
|
|
@@ -16,12 +20,13 @@ const BASE_DIMENSIONS: Record<string, '1d' | '2d' | '3d'> = {
|
|
|
16
20
|
export class WebGPUTexture extends Texture {
|
|
17
21
|
readonly device: WebGPUDevice;
|
|
18
22
|
readonly handle: GPUTexture;
|
|
19
|
-
readonly view: GPUTextureView;
|
|
20
|
-
sampler: WebGPUSampler;
|
|
21
23
|
|
|
22
24
|
override height: number = 1;
|
|
23
25
|
override width: number = 1;
|
|
24
26
|
|
|
27
|
+
sampler: WebGPUSampler;
|
|
28
|
+
view: WebGPUTextureView;
|
|
29
|
+
|
|
25
30
|
// static async createFromImageURL(src, usage = 0) {
|
|
26
31
|
// const img = document.createElement('img');
|
|
27
32
|
// img.src = src;
|
|
@@ -46,6 +51,16 @@ export class WebGPUTexture extends Texture {
|
|
|
46
51
|
this.initialize(props);
|
|
47
52
|
}
|
|
48
53
|
|
|
54
|
+
override destroy(): void {
|
|
55
|
+
this.handle?.destroy();
|
|
56
|
+
// @ts-expect-error readonly
|
|
57
|
+
this.handle = null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
createView(props: TextureViewProps): WebGPUTextureView {
|
|
61
|
+
return new WebGPUTextureView(this.device, {...props, texture: this});
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
protected initialize(props: TextureProps): void {
|
|
50
65
|
// @ts-expect-error
|
|
51
66
|
this.handle = this.props.handle || this.createHandle();
|
|
@@ -67,12 +82,16 @@ export class WebGPUTexture extends Texture {
|
|
|
67
82
|
|
|
68
83
|
// Create a default sampler. This mimics the WebGL1 API where sampler props are stored on the texture
|
|
69
84
|
// this.setSampler(props.sampler);
|
|
70
|
-
this.sampler =
|
|
85
|
+
this.sampler =
|
|
86
|
+
props.sampler instanceof WebGPUSampler
|
|
87
|
+
? props.sampler
|
|
88
|
+
: new WebGPUSampler(this.device, props.sampler);
|
|
71
89
|
|
|
72
90
|
// TODO - To support texture arrays we need to create custom views...
|
|
73
91
|
// But we are not ready to expose TextureViews to the public API.
|
|
74
92
|
// @ts-expect-error
|
|
75
|
-
|
|
93
|
+
|
|
94
|
+
this.view = new WebGPUTextureView(this.device, {...this.props, texture: this});
|
|
76
95
|
// format: this.props.format,
|
|
77
96
|
// dimension: this.props.dimension,
|
|
78
97
|
// aspect = "all";
|
|
@@ -104,22 +123,17 @@ export class WebGPUTexture extends Texture {
|
|
|
104
123
|
});
|
|
105
124
|
}
|
|
106
125
|
|
|
107
|
-
override destroy(): void {
|
|
108
|
-
this.handle.destroy();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
126
|
/**
|
|
112
127
|
* Set default sampler
|
|
113
128
|
* Accept a sampler instance or set of props;
|
|
114
129
|
*/
|
|
115
130
|
setSampler(sampler: Sampler | SamplerProps): this {
|
|
116
|
-
this.sampler =
|
|
131
|
+
this.sampler =
|
|
132
|
+
sampler instanceof WebGPUSampler ? sampler : new WebGPUSampler(this.device, sampler);
|
|
117
133
|
return this;
|
|
118
134
|
}
|
|
119
135
|
|
|
120
|
-
setData(options: {
|
|
121
|
-
data: any;
|
|
122
|
-
}) {
|
|
136
|
+
setData(options: {data: any}) {
|
|
123
137
|
return this.setImage({source: options.data});
|
|
124
138
|
}
|
|
125
139
|
|
|
@@ -138,7 +152,7 @@ export class WebGPUTexture extends Texture {
|
|
|
138
152
|
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
139
153
|
colorSpace?: 'srgb';
|
|
140
154
|
premultipliedAlpha?: boolean;
|
|
141
|
-
}): {width: number
|
|
155
|
+
}): {width: number; height: number} {
|
|
142
156
|
const {
|
|
143
157
|
source,
|
|
144
158
|
width = options.source.width,
|
|
@@ -173,22 +187,13 @@ export class WebGPUTexture extends Texture {
|
|
|
173
187
|
premultipliedAlpha
|
|
174
188
|
},
|
|
175
189
|
// copySize: GPUExtent3D
|
|
176
|
-
[
|
|
177
|
-
width,
|
|
178
|
-
height,
|
|
179
|
-
depth
|
|
180
|
-
]
|
|
190
|
+
[width, height, depth]
|
|
181
191
|
);
|
|
182
192
|
return {width, height};
|
|
183
193
|
}
|
|
184
194
|
|
|
185
|
-
// WebGPU specific
|
|
186
|
-
|
|
187
|
-
/** TODO - intention is to expose TextureViews in the public API */
|
|
188
|
-
createView(): GPUTextureView {
|
|
189
|
-
return this.handle.createView({label: this.id});
|
|
190
|
-
}
|
|
191
|
-
|
|
195
|
+
// WebGPU specific
|
|
196
|
+
|
|
192
197
|
/*
|
|
193
198
|
async readPixels() {
|
|
194
199
|
const readbackBuffer = device.createBuffer({
|