@luma.gl/webgpu 9.2.6 → 9.3.0-alpha.4
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/get-bind-group.d.ts.map +1 -1
- package/dist/adapter/helpers/get-bind-group.js +11 -5
- package/dist/adapter/helpers/get-bind-group.js.map +1 -1
- package/dist/adapter/resources/webgpu-buffer.d.ts +7 -0
- package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-buffer.js +39 -12
- package/dist/adapter/resources/webgpu-buffer.js.map +1 -1
- package/dist/adapter/resources/webgpu-fence.d.ts +13 -0
- package/dist/adapter/resources/webgpu-fence.d.ts.map +1 -0
- package/dist/adapter/resources/webgpu-fence.js +25 -0
- package/dist/adapter/resources/webgpu-fence.js.map +1 -0
- package/dist/adapter/resources/webgpu-pipeline-layout.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-pipeline-layout.js +1 -2
- package/dist/adapter/resources/webgpu-pipeline-layout.js.map +1 -1
- package/dist/adapter/resources/webgpu-texture.d.ts +12 -3
- package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-texture.js +143 -26
- package/dist/adapter/resources/webgpu-texture.js.map +1 -1
- package/dist/adapter/webgpu-adapter.d.ts.map +1 -1
- package/dist/adapter/webgpu-adapter.js +34 -34
- package/dist/adapter/webgpu-adapter.js.map +1 -1
- package/dist/adapter/webgpu-canvas-context.d.ts +4 -3
- package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
- package/dist/adapter/webgpu-canvas-context.js +22 -21
- package/dist/adapter/webgpu-canvas-context.js.map +1 -1
- package/dist/adapter/webgpu-device.d.ts +3 -1
- package/dist/adapter/webgpu-device.d.ts.map +1 -1
- package/dist/adapter/webgpu-device.js +14 -3
- package/dist/adapter/webgpu-device.js.map +1 -1
- package/dist/dist.dev.js +6485 -293
- package/dist/dist.min.js +10 -6
- package/dist/index.cjs +398 -114
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/wgsl/get-shader-layout-wgsl.d.ts +8 -0
- package/dist/wgsl/get-shader-layout-wgsl.d.ts.map +1 -0
- package/dist/wgsl/get-shader-layout-wgsl.js +136 -0
- package/dist/wgsl/get-shader-layout-wgsl.js.map +1 -0
- package/package.json +6 -5
- package/src/adapter/helpers/get-bind-group.ts +18 -5
- package/src/adapter/resources/webgpu-buffer.ts +43 -12
- package/src/adapter/resources/webgpu-fence.ts +30 -0
- package/src/adapter/resources/webgpu-pipeline-layout.ts +1 -2
- package/src/adapter/resources/webgpu-texture.ts +202 -88
- package/src/adapter/webgpu-adapter.ts +40 -42
- package/src/adapter/webgpu-canvas-context.ts +25 -23
- package/src/adapter/webgpu-device.ts +19 -4
- package/src/index.ts +3 -0
- package/src/wgsl/get-shader-layout-wgsl.ts +156 -0
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
// luma.gl, MIT license
|
|
2
|
-
import
|
|
3
|
-
TextureProps,
|
|
4
|
-
TextureViewProps,
|
|
5
|
-
CopyExternalImageOptions,
|
|
6
|
-
CopyImageDataOptions,
|
|
7
|
-
|
|
2
|
+
import {
|
|
3
|
+
type TextureProps,
|
|
4
|
+
type TextureViewProps,
|
|
5
|
+
type CopyExternalImageOptions,
|
|
6
|
+
type CopyImageDataOptions,
|
|
7
|
+
type TextureReadOptions,
|
|
8
|
+
type TextureWriteOptions,
|
|
9
|
+
type SamplerProps,
|
|
10
|
+
Buffer,
|
|
11
|
+
Texture,
|
|
12
|
+
log,
|
|
13
|
+
textureFormatDecoder
|
|
8
14
|
} from '@luma.gl/core';
|
|
9
|
-
import {Texture, log} from '@luma.gl/core';
|
|
10
15
|
|
|
11
16
|
import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
|
|
12
17
|
import type {WebGPUDevice} from '../webgpu-device';
|
|
13
18
|
import {WebGPUSampler} from './webgpu-sampler';
|
|
14
19
|
import {WebGPUTextureView} from './webgpu-texture-view';
|
|
15
20
|
|
|
21
|
+
/** WebGPU implementation of the luma.gl core Texture resource */
|
|
16
22
|
export class WebGPUTexture extends Texture {
|
|
17
23
|
readonly device: WebGPUDevice;
|
|
18
24
|
readonly handle: GPUTexture;
|
|
@@ -20,13 +26,9 @@ export class WebGPUTexture extends Texture {
|
|
|
20
26
|
view: WebGPUTextureView;
|
|
21
27
|
|
|
22
28
|
constructor(device: WebGPUDevice, props: TextureProps) {
|
|
23
|
-
super(device, props);
|
|
29
|
+
super(device, props, {byteAlignment: 256}); // WebGPU requires row width to be a multiple of 256 bytes
|
|
24
30
|
this.device = device;
|
|
25
31
|
|
|
26
|
-
if (this.dimension === 'cube') {
|
|
27
|
-
this.depth = 6;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
32
|
this.device.pushErrorScope('out-of-memory');
|
|
31
33
|
this.device.pushErrorScope('validation');
|
|
32
34
|
|
|
@@ -58,7 +60,9 @@ export class WebGPUTexture extends Texture {
|
|
|
58
60
|
// TODO - Read all properties directly from the supplied handle?
|
|
59
61
|
if (this.props.handle) {
|
|
60
62
|
this.handle.label ||= this.id;
|
|
63
|
+
// @ts-expect-error readonly
|
|
61
64
|
this.width = this.handle.width;
|
|
65
|
+
// @ts-expect-error readonly
|
|
62
66
|
this.height = this.handle.height;
|
|
63
67
|
}
|
|
64
68
|
|
|
@@ -90,10 +94,43 @@ export class WebGPUTexture extends Texture {
|
|
|
90
94
|
return new WebGPUTextureView(this.device, {...props, texture: this});
|
|
91
95
|
}
|
|
92
96
|
|
|
97
|
+
copyExternalImage(options_: CopyExternalImageOptions): {width: number; height: number} {
|
|
98
|
+
const options = this._normalizeCopyExternalImageOptions(options_);
|
|
99
|
+
|
|
100
|
+
this.device.pushErrorScope('validation');
|
|
101
|
+
this.device.handle.queue.copyExternalImageToTexture(
|
|
102
|
+
// source: GPUImageCopyExternalImage
|
|
103
|
+
{
|
|
104
|
+
source: options.image,
|
|
105
|
+
origin: [options.sourceX, options.sourceY],
|
|
106
|
+
flipY: false // options.flipY
|
|
107
|
+
},
|
|
108
|
+
// destination: GPUImageCopyTextureTagged
|
|
109
|
+
{
|
|
110
|
+
texture: this.handle,
|
|
111
|
+
origin: [options.x, options.y, options.z],
|
|
112
|
+
mipLevel: options.mipLevel,
|
|
113
|
+
aspect: options.aspect,
|
|
114
|
+
colorSpace: options.colorSpace,
|
|
115
|
+
premultipliedAlpha: options.premultipliedAlpha
|
|
116
|
+
},
|
|
117
|
+
// copySize: GPUExtent3D
|
|
118
|
+
[options.width, options.height, options.depth] // depth is always 1 for 2D textures
|
|
119
|
+
);
|
|
120
|
+
this.device.popErrorScope((error: GPUError) => {
|
|
121
|
+
this.device.reportError(new Error(`copyExternalImage: ${error.message}`), this)();
|
|
122
|
+
this.device.debug();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// TODO - should these be clipped to the texture size minus x,y,z?
|
|
126
|
+
return {width: options.width, height: options.height};
|
|
127
|
+
}
|
|
128
|
+
|
|
93
129
|
copyImageData(options_: CopyImageDataOptions): void {
|
|
94
130
|
const {width, height, depth} = this;
|
|
95
131
|
const options = this._normalizeCopyImageDataOptions(options_);
|
|
96
132
|
this.device.pushErrorScope('validation');
|
|
133
|
+
|
|
97
134
|
this.device.handle.queue.writeTexture(
|
|
98
135
|
// destination: GPUImageCopyTexture
|
|
99
136
|
{
|
|
@@ -121,108 +158,185 @@ export class WebGPUTexture extends Texture {
|
|
|
121
158
|
});
|
|
122
159
|
}
|
|
123
160
|
|
|
124
|
-
|
|
125
|
-
|
|
161
|
+
override generateMipmapsWebGL(): void {
|
|
162
|
+
log.warn(`${this}: generateMipmaps not supported in WebGPU`)();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
getImageDataLayout(options: TextureReadOptions): {
|
|
166
|
+
byteLength: number;
|
|
167
|
+
bytesPerRow: number;
|
|
168
|
+
rowsPerImage: number;
|
|
169
|
+
} {
|
|
170
|
+
return {
|
|
171
|
+
byteLength: 0,
|
|
172
|
+
bytesPerRow: 0,
|
|
173
|
+
rowsPerImage: 0
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
override readBuffer(options: TextureReadOptions = {}, buffer?: Buffer): Buffer {
|
|
178
|
+
const {
|
|
179
|
+
x = 0,
|
|
180
|
+
y = 0,
|
|
181
|
+
z = 0,
|
|
182
|
+
width = this.width,
|
|
183
|
+
height = this.height,
|
|
184
|
+
depthOrArrayLayers = this.depth,
|
|
185
|
+
mipLevel = 0,
|
|
186
|
+
aspect = 'all'
|
|
187
|
+
} = options;
|
|
188
|
+
|
|
189
|
+
const layout = this.computeMemoryLayout(options);
|
|
190
|
+
|
|
191
|
+
const {bytesPerRow, rowsPerImage, byteLength} = layout;
|
|
192
|
+
|
|
193
|
+
// Create a GPUBuffer to hold the copied pixel data.
|
|
194
|
+
const readBuffer =
|
|
195
|
+
buffer ||
|
|
196
|
+
this.device.createBuffer({
|
|
197
|
+
byteLength,
|
|
198
|
+
usage: Buffer.COPY_DST | Buffer.MAP_READ
|
|
199
|
+
});
|
|
200
|
+
const gpuReadBuffer = readBuffer.handle as GPUBuffer;
|
|
201
|
+
|
|
202
|
+
// Record commands to copy from the texture to the buffer.
|
|
203
|
+
const gpuDevice = this.device.handle;
|
|
126
204
|
|
|
127
205
|
this.device.pushErrorScope('validation');
|
|
128
|
-
|
|
129
|
-
|
|
206
|
+
const commandEncoder = gpuDevice.createCommandEncoder();
|
|
207
|
+
commandEncoder.copyTextureToBuffer(
|
|
208
|
+
// source
|
|
130
209
|
{
|
|
131
|
-
|
|
132
|
-
origin:
|
|
133
|
-
|
|
210
|
+
texture: this.handle,
|
|
211
|
+
origin: {x, y, z},
|
|
212
|
+
// origin: [options.x, options.y, 0], // options.depth],
|
|
213
|
+
mipLevel,
|
|
214
|
+
aspect
|
|
215
|
+
// colorSpace: options.colorSpace,
|
|
216
|
+
// premultipliedAlpha: options.premultipliedAlpha
|
|
134
217
|
},
|
|
135
|
-
// destination
|
|
218
|
+
// destination
|
|
136
219
|
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
colorSpace: options.colorSpace,
|
|
142
|
-
premultipliedAlpha: options.premultipliedAlpha
|
|
220
|
+
buffer: gpuReadBuffer,
|
|
221
|
+
offset: 0,
|
|
222
|
+
bytesPerRow,
|
|
223
|
+
rowsPerImage
|
|
143
224
|
},
|
|
144
|
-
//
|
|
145
|
-
|
|
225
|
+
// copy size
|
|
226
|
+
{
|
|
227
|
+
width,
|
|
228
|
+
height,
|
|
229
|
+
depthOrArrayLayers
|
|
230
|
+
}
|
|
146
231
|
);
|
|
232
|
+
|
|
233
|
+
// Submit the command.
|
|
234
|
+
const commandBuffer = commandEncoder.finish();
|
|
235
|
+
this.device.handle.queue.submit([commandBuffer]);
|
|
147
236
|
this.device.popErrorScope((error: GPUError) => {
|
|
148
|
-
this.device.reportError(new Error(
|
|
237
|
+
this.device.reportError(new Error(`${this} readBuffer: ${error.message}`), this)();
|
|
149
238
|
this.device.debug();
|
|
150
239
|
});
|
|
151
240
|
|
|
152
|
-
|
|
153
|
-
return {width: options.width, height: options.height};
|
|
241
|
+
return readBuffer;
|
|
154
242
|
}
|
|
155
243
|
|
|
156
|
-
override
|
|
157
|
-
|
|
244
|
+
override async readDataAsync(options: TextureReadOptions = {}): Promise<ArrayBuffer> {
|
|
245
|
+
const buffer = this.readBuffer(options);
|
|
246
|
+
const data = await buffer.readAsync();
|
|
247
|
+
buffer.destroy();
|
|
248
|
+
return data.buffer as ArrayBuffer;
|
|
158
249
|
}
|
|
159
250
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
251
|
+
override writeBuffer(buffer: Buffer, options: TextureWriteOptions = {}) {
|
|
252
|
+
const {
|
|
253
|
+
x = 0,
|
|
254
|
+
y = 0,
|
|
255
|
+
z = 0,
|
|
256
|
+
width = this.width,
|
|
257
|
+
height = this.height,
|
|
258
|
+
depthOrArrayLayers = this.depth,
|
|
259
|
+
mipLevel = 0,
|
|
260
|
+
aspect = 'all'
|
|
261
|
+
} = options;
|
|
168
262
|
|
|
169
|
-
|
|
170
|
-
const encoder = device.createCommandEncoder();
|
|
171
|
-
encoder.copyTextureToBuffer(
|
|
172
|
-
{ texture },
|
|
173
|
-
{ buffer, rowPitch: textureWidth * 4 },
|
|
174
|
-
[textureWidth, textureHeight],
|
|
175
|
-
);
|
|
176
|
-
device.submit([encoder.finish()]);
|
|
263
|
+
const layout = this.computeMemoryLayout(options);
|
|
177
264
|
|
|
178
265
|
// Get the data on the CPU.
|
|
179
|
-
await buffer.mapAndReadAsync(
|
|
180
|
-
saveScreenshot(buffer.getMappedRange());
|
|
181
|
-
buffer.unmap();
|
|
182
|
-
}
|
|
266
|
+
// await buffer.mapAndReadAsync();
|
|
183
267
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const bytesPerRow = Math.ceil((img.width * 4) / 256) * 256;
|
|
188
|
-
if (bytesPerRow == img.width * 4) {
|
|
189
|
-
data = imageData.data;
|
|
190
|
-
} else {
|
|
191
|
-
data = new Uint8Array(bytesPerRow * img.height);
|
|
192
|
-
let imagePixelIndex = 0;
|
|
193
|
-
for (let y = 0; y < img.height; ++y) {
|
|
194
|
-
for (let x = 0; x < img.width; ++x) {
|
|
195
|
-
const i = x * 4 + y * bytesPerRow;
|
|
196
|
-
data[i] = imageData.data[imagePixelIndex];
|
|
197
|
-
data[i + 1] = imageData.data[imagePixelIndex + 1];
|
|
198
|
-
data[i + 2] = imageData.data[imagePixelIndex + 2];
|
|
199
|
-
data[i + 3] = imageData.data[imagePixelIndex + 3];
|
|
200
|
-
imagePixelIndex += 4;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return this;
|
|
205
|
-
}
|
|
268
|
+
const {bytesPerRow, rowsPerImage} = layout;
|
|
269
|
+
|
|
270
|
+
const gpuDevice = this.device.handle;
|
|
206
271
|
|
|
207
|
-
|
|
208
|
-
const commandEncoder =
|
|
272
|
+
this.device.pushErrorScope('validation');
|
|
273
|
+
const commandEncoder = gpuDevice.createCommandEncoder();
|
|
209
274
|
commandEncoder.copyBufferToTexture(
|
|
210
275
|
{
|
|
211
|
-
buffer:
|
|
212
|
-
|
|
276
|
+
buffer: buffer.handle as GPUBuffer,
|
|
277
|
+
offset: 0,
|
|
278
|
+
bytesPerRow,
|
|
279
|
+
rowsPerImage
|
|
213
280
|
},
|
|
214
281
|
{
|
|
215
|
-
texture: this.handle
|
|
282
|
+
texture: this.handle,
|
|
283
|
+
origin: {x, y, z},
|
|
284
|
+
mipLevel,
|
|
285
|
+
aspect
|
|
216
286
|
},
|
|
217
|
-
{
|
|
218
|
-
width,
|
|
219
|
-
height,
|
|
220
|
-
depth
|
|
221
|
-
}
|
|
287
|
+
{width, height, depthOrArrayLayers}
|
|
222
288
|
);
|
|
289
|
+
const commandBuffer = commandEncoder.finish();
|
|
290
|
+
this.device.handle.queue.submit([commandBuffer]);
|
|
291
|
+
this.device.popErrorScope((error: GPUError) => {
|
|
292
|
+
this.device.reportError(new Error(`${this} writeBuffer: ${error.message}`), this)();
|
|
293
|
+
this.device.debug();
|
|
294
|
+
});
|
|
295
|
+
}
|
|
223
296
|
|
|
224
|
-
|
|
225
|
-
|
|
297
|
+
override writeData(data: ArrayBuffer | ArrayBufferView, options: TextureWriteOptions = {}): void {
|
|
298
|
+
const device = this.device;
|
|
299
|
+
|
|
300
|
+
const {
|
|
301
|
+
x = 0,
|
|
302
|
+
y = 0,
|
|
303
|
+
z = 0,
|
|
304
|
+
width = this.width,
|
|
305
|
+
height = this.height,
|
|
306
|
+
depthOrArrayLayers = this.depth,
|
|
307
|
+
mipLevel = 0,
|
|
308
|
+
aspect = 'all'
|
|
309
|
+
} = options;
|
|
310
|
+
|
|
311
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
312
|
+
format: this.format,
|
|
313
|
+
width: this.width,
|
|
314
|
+
height: this.height,
|
|
315
|
+
depth: this.depth,
|
|
316
|
+
byteAlignment: this.byteAlignment
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const {bytesPerRow, rowsPerImage} = layout;
|
|
320
|
+
|
|
321
|
+
this.device.pushErrorScope('validation');
|
|
322
|
+
device.handle.queue.writeTexture(
|
|
323
|
+
{
|
|
324
|
+
texture: this.handle,
|
|
325
|
+
mipLevel,
|
|
326
|
+
aspect,
|
|
327
|
+
origin: {x, y, z}
|
|
328
|
+
},
|
|
329
|
+
data,
|
|
330
|
+
{
|
|
331
|
+
offset: 0,
|
|
332
|
+
bytesPerRow,
|
|
333
|
+
rowsPerImage
|
|
334
|
+
},
|
|
335
|
+
{width, height, depthOrArrayLayers}
|
|
336
|
+
);
|
|
337
|
+
this.device.popErrorScope((error: GPUError) => {
|
|
338
|
+
this.device.reportError(new Error(`${this} writeData: ${error.message}`), this)();
|
|
339
|
+
this.device.debug();
|
|
340
|
+
});
|
|
226
341
|
}
|
|
227
|
-
*/
|
|
228
342
|
}
|
|
@@ -35,62 +35,60 @@ export class WebGPUAdapter extends Adapter {
|
|
|
35
35
|
throw new Error('WebGPU not available. Recent Chrome browsers should work.');
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// forceSoftware: false
|
|
43
|
-
});
|
|
38
|
+
const adapter = await navigator.gpu.requestAdapter({
|
|
39
|
+
powerPreference: 'high-performance'
|
|
40
|
+
// forceSoftware: false
|
|
41
|
+
});
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
if (!adapter) {
|
|
44
|
+
throw new Error('Failed to request WebGPU adapter');
|
|
45
|
+
}
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
47
|
+
// Note: adapter.requestAdapterInfo() has been replaced with adapter.info. Fall back in case adapter.info is not available
|
|
48
|
+
const adapterInfo =
|
|
49
|
+
adapter.info ||
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
(await adapter.requestAdapterInfo?.());
|
|
52
|
+
// log.probe(2, 'Adapter available', adapterInfo)();
|
|
53
|
+
|
|
54
|
+
const requiredFeatures: GPUFeatureName[] = [];
|
|
55
|
+
const requiredLimits: Record<string, number> = {};
|
|
56
|
+
|
|
57
|
+
if (props._requestMaxLimits) {
|
|
58
|
+
// Require all features
|
|
59
|
+
requiredFeatures.push(...(Array.from(adapter.features) as GPUFeatureName[]));
|
|
60
|
+
|
|
61
|
+
// Require all limits
|
|
62
|
+
// Filter out chrome specific keys (avoid crash)
|
|
63
|
+
const limits = Object.keys(adapter.limits).filter(
|
|
64
|
+
key => !['minSubgroupSize', 'maxSubgroupSize'].includes(key)
|
|
65
|
+
);
|
|
66
|
+
for (const key of limits) {
|
|
67
|
+
const limit = key as keyof GPUSupportedLimits;
|
|
68
|
+
const value = adapter.limits[limit];
|
|
69
|
+
if (typeof value === 'number') {
|
|
70
|
+
requiredLimits[limit] = value;
|
|
74
71
|
}
|
|
75
72
|
}
|
|
73
|
+
}
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
const gpuDevice = await adapter.requestDevice({
|
|
76
|
+
requiredFeatures,
|
|
77
|
+
requiredLimits
|
|
78
|
+
});
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
// log.probe(1, 'GPUDevice available')();
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
const {WebGPUDevice} = await import('./webgpu-device');
|
|
85
83
|
|
|
84
|
+
log.groupCollapsed(1, 'WebGPUDevice created')();
|
|
85
|
+
try {
|
|
86
86
|
const device = new WebGPUDevice(props, gpuDevice, adapter, adapterInfo);
|
|
87
|
-
|
|
88
87
|
log.probe(
|
|
89
88
|
1,
|
|
90
89
|
'Device created. For more info, set chrome://flags/#enable-webgpu-developer-features'
|
|
91
90
|
)();
|
|
92
91
|
log.table(1, device.info)();
|
|
93
|
-
|
|
94
92
|
return device;
|
|
95
93
|
} finally {
|
|
96
94
|
log.groupEnd(1)();
|
|
@@ -38,7 +38,7 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
38
38
|
|
|
39
39
|
// Base class constructor cannot access derived methods/fields, so we need to call these functions in the subclass constructor
|
|
40
40
|
this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
|
|
41
|
-
this.
|
|
41
|
+
this._configureDevice();
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/** Destroy any textures produced while configured and remove the context configuration. */
|
|
@@ -47,14 +47,34 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
47
47
|
super.destroy();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// IMPLEMENTATION OF ABSTRACT METHODS
|
|
51
|
+
|
|
52
|
+
/** @see https://www.w3.org/TR/webgpu/#canvas-configuration */
|
|
53
|
+
_configureDevice(): void {
|
|
54
|
+
if (this.depthStencilAttachment) {
|
|
55
|
+
this.depthStencilAttachment.destroy();
|
|
56
|
+
this.depthStencilAttachment = null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Reconfigure the canvas size.
|
|
60
|
+
this.handle.configure({
|
|
61
|
+
device: this.device.handle,
|
|
62
|
+
format: this.device.preferredColorFormat,
|
|
63
|
+
// Can be used to define e.g. -srgb views
|
|
64
|
+
// viewFormats: [...]
|
|
65
|
+
colorSpace: this.props.colorSpace,
|
|
66
|
+
alphaMode: this.props.alphaMode
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
50
70
|
/** Update framebuffer with properly resized "swap chain" texture views */
|
|
51
|
-
|
|
71
|
+
_getCurrentFramebuffer(
|
|
52
72
|
options: {depthStencilFormat?: TextureFormatDepthStencil | false} = {
|
|
53
73
|
depthStencilFormat: 'depth24plus'
|
|
54
74
|
}
|
|
55
75
|
): WebGPUFramebuffer {
|
|
56
76
|
// Wrap the current canvas context texture in a luma.gl texture
|
|
57
|
-
const currentColorAttachment = this.
|
|
77
|
+
const currentColorAttachment = this._getCurrentTexture();
|
|
58
78
|
// TODO - temporary debug code
|
|
59
79
|
if (
|
|
60
80
|
currentColorAttachment.width !== this.drawingBufferWidth ||
|
|
@@ -80,28 +100,10 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
80
100
|
});
|
|
81
101
|
}
|
|
82
102
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
_updateDevice(): void {
|
|
86
|
-
if (this.depthStencilAttachment) {
|
|
87
|
-
this.depthStencilAttachment.destroy();
|
|
88
|
-
this.depthStencilAttachment = null;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Reconfigure the canvas size.
|
|
92
|
-
// https://www.w3.org/TR/webgpu/#canvas-configuration
|
|
93
|
-
this.handle.configure({
|
|
94
|
-
device: this.device.handle,
|
|
95
|
-
format: this.device.preferredColorFormat,
|
|
96
|
-
// Can be used to define e.g. -srgb views
|
|
97
|
-
// viewFormats: [...]
|
|
98
|
-
colorSpace: this.props.colorSpace,
|
|
99
|
-
alphaMode: this.props.alphaMode
|
|
100
|
-
});
|
|
101
|
-
}
|
|
103
|
+
// PRIMARY METHODS
|
|
102
104
|
|
|
103
105
|
/** Wrap the current canvas context texture in a luma.gl texture */
|
|
104
|
-
|
|
106
|
+
_getCurrentTexture(): WebGPUTexture {
|
|
105
107
|
const handle = this.handle.getCurrentTexture();
|
|
106
108
|
return this.device.createTexture({
|
|
107
109
|
id: `${this.id}#color-texture`,
|
|
@@ -45,6 +45,9 @@ import {WebGPUCommandEncoder} from './resources/webgpu-command-encoder';
|
|
|
45
45
|
import {WebGPUCommandBuffer} from './resources/webgpu-command-buffer';
|
|
46
46
|
import {WebGPUQuerySet} from './resources/webgpu-query-set';
|
|
47
47
|
import {WebGPUPipelineLayout} from './resources/webgpu-pipeline-layout';
|
|
48
|
+
import {WebGPUFence} from './resources/webgpu-fence';
|
|
49
|
+
|
|
50
|
+
import {getShaderLayoutFromWGSL} from '../wgsl/get-shader-layout-wgsl';
|
|
48
51
|
|
|
49
52
|
/** WebGPU Device implementation */
|
|
50
53
|
export class WebGPUDevice extends Device {
|
|
@@ -136,15 +139,15 @@ export class WebGPUDevice extends Device {
|
|
|
136
139
|
return this._isLost;
|
|
137
140
|
}
|
|
138
141
|
|
|
142
|
+
getShaderLayout(source: string) {
|
|
143
|
+
return getShaderLayoutFromWGSL(source);
|
|
144
|
+
}
|
|
145
|
+
|
|
139
146
|
override isVertexFormatSupported(format: VertexFormat): boolean {
|
|
140
147
|
const info = this.getVertexFormatInfo(format);
|
|
141
148
|
return !info.webglOnly;
|
|
142
149
|
}
|
|
143
150
|
|
|
144
|
-
getTextureByteAlignment(): number {
|
|
145
|
-
return 1;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
151
|
createBuffer(props: BufferProps | ArrayBuffer | ArrayBufferView): WebGPUBuffer {
|
|
149
152
|
const newProps = this._normalizeBufferProps(props);
|
|
150
153
|
return new WebGPUBuffer(this, newProps);
|
|
@@ -196,6 +199,10 @@ export class WebGPUDevice extends Device {
|
|
|
196
199
|
return new WebGPUQuerySet(this, props);
|
|
197
200
|
}
|
|
198
201
|
|
|
202
|
+
override createFence(): WebGPUFence {
|
|
203
|
+
return new WebGPUFence(this);
|
|
204
|
+
}
|
|
205
|
+
|
|
199
206
|
createCanvasContext(props: CanvasContextProps): WebGPUCanvasContext {
|
|
200
207
|
return new WebGPUCanvasContext(this, this.adapter, props);
|
|
201
208
|
}
|
|
@@ -278,6 +285,14 @@ export class WebGPUDevice extends Device {
|
|
|
278
285
|
features.add('texture-compression-bc5-webgl');
|
|
279
286
|
}
|
|
280
287
|
|
|
288
|
+
if (this.handle.features.has('chromium-experimental-norm16-texture-formats')) {
|
|
289
|
+
features.add('norm16-renderable-webgl');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (this.handle.features.has('chromium-experimental-snorm16-texture-formats')) {
|
|
293
|
+
features.add('snorm16-renderable-webgl');
|
|
294
|
+
}
|
|
295
|
+
|
|
281
296
|
const WEBGPU_ALWAYS_FEATURES: DeviceFeature[] = [
|
|
282
297
|
'timer-query-webgl',
|
|
283
298
|
'compilation-status-async-webgl',
|
package/src/index.ts
CHANGED
|
@@ -12,3 +12,6 @@ export {WebGPUBuffer} from './adapter/resources/webgpu-buffer';
|
|
|
12
12
|
export {WebGPUTexture} from './adapter/resources/webgpu-texture';
|
|
13
13
|
export {WebGPUSampler} from './adapter/resources/webgpu-sampler';
|
|
14
14
|
export {WebGPUShader} from './adapter/resources/webgpu-shader';
|
|
15
|
+
export {WebGPUFence} from './adapter/resources/webgpu-fence';
|
|
16
|
+
|
|
17
|
+
export {getShaderLayoutFromWGSL} from './wgsl/get-shader-layout-wgsl';
|