@luma.gl/webgpu 9.0.0-alpha.34 → 9.0.0-alpha.36

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.
Files changed (40) hide show
  1. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
  2. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -1
  3. package/dist/adapter/helpers/webgpu-parameters.js +2 -2
  4. package/dist/adapter/helpers/webgpu-parameters.js.map +1 -1
  5. package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
  6. package/dist/adapter/resources/webgpu-render-pass.js +23 -4
  7. package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
  8. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +3 -2
  9. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  10. package/dist/adapter/resources/webgpu-render-pipeline.js +11 -12
  11. package/dist/adapter/resources/webgpu-render-pipeline.js.map +1 -1
  12. package/dist/adapter/resources/webgpu-shader.js +1 -1
  13. package/dist/adapter/resources/webgpu-shader.js.map +1 -1
  14. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  15. package/dist/adapter/resources/webgpu-texture.js.map +1 -1
  16. package/dist/adapter/resources/webgpu-vertex-array.d.ts +26 -0
  17. package/dist/adapter/resources/webgpu-vertex-array.d.ts.map +1 -0
  18. package/dist/adapter/resources/webgpu-vertex-array.js +39 -0
  19. package/dist/adapter/resources/webgpu-vertex-array.js.map +1 -0
  20. package/dist/adapter/webgpu-canvas-context.d.ts +8 -2
  21. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
  22. package/dist/adapter/webgpu-canvas-context.js +11 -10
  23. package/dist/adapter/webgpu-canvas-context.js.map +1 -1
  24. package/dist/adapter/webgpu-device.d.ts +4 -1
  25. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  26. package/dist/adapter/webgpu-device.js +10 -14
  27. package/dist/adapter/webgpu-device.js.map +1 -1
  28. package/dist/dist.dev.js +250 -110
  29. package/dist/index.cjs +130 -59
  30. package/dist.min.js +5 -5
  31. package/package.json +3 -3
  32. package/src/adapter/helpers/get-vertex-buffer-layout.ts +1 -0
  33. package/src/adapter/helpers/webgpu-parameters.ts +2 -2
  34. package/src/adapter/resources/webgpu-render-pass.ts +27 -4
  35. package/src/adapter/resources/webgpu-render-pipeline.ts +18 -15
  36. package/src/adapter/resources/webgpu-shader.ts +1 -1
  37. package/src/adapter/resources/webgpu-texture.ts +7 -0
  38. package/src/adapter/resources/webgpu-vertex-array.ts +73 -0
  39. package/src/adapter/webgpu-canvas-context.ts +36 -16
  40. package/src/adapter/webgpu-device.ts +21 -13
@@ -32,13 +32,20 @@ export class WebGPURenderPipeline extends RenderPipeline {
32
32
  // private _lastIndex: number;
33
33
 
34
34
  /** For internal use to create BindGroups */
35
- private _bindGroupLayout: GPUBindGroupLayout;
35
+ private _bindGroupLayout: GPUBindGroupLayout | null = null;
36
36
  private _bindGroup: GPUBindGroup | null = null;
37
37
 
38
38
  constructor(device: WebGPUDevice, props: RenderPipelineProps) {
39
39
  super(device, props);
40
40
  this.device = device;
41
- this.handle = (this.props.handle as GPURenderPipeline) || this.createHandle();
41
+ this.handle = this.props.handle as GPURenderPipeline;
42
+ if (!this.handle) {
43
+ const descriptor = this._getRenderPipelineDescriptor();
44
+ log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
45
+ log.probe(1, JSON.stringify(descriptor, null, 2))();
46
+ log.groupEnd(1)();
47
+ this.handle = this.device.handle.createRenderPipeline(descriptor);
48
+ }
42
49
  this.handle.label = this.props.id;
43
50
 
44
51
  this.vs = cast<WebGPUShader>(props.vs);
@@ -46,16 +53,6 @@ export class WebGPURenderPipeline extends RenderPipeline {
46
53
 
47
54
  this._bufferSlots = getBufferSlots(this.props.shaderLayout, this.props.bufferLayout);
48
55
  this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
49
- this._bindGroupLayout = this.handle.getBindGroupLayout(0);
50
- }
51
-
52
- protected createHandle(): GPURenderPipeline {
53
- const descriptor = this._getRenderPipelineDescriptor();
54
- const renderPipeline = this.device.handle.createRenderPipeline(descriptor);
55
- log.groupCollapsed(1, `new WebGPRenderPipeline(${this.id})`)();
56
- log.log(1, JSON.stringify(descriptor, null, 2))();
57
- log.groupEnd(1)();
58
- return renderPipeline;
59
56
  }
60
57
 
61
58
  override destroy(): void {
@@ -91,7 +88,12 @@ export class WebGPURenderPipeline extends RenderPipeline {
91
88
 
92
89
  setBindings(bindings: Record<string, Binding>): void {
93
90
  if (!isObjectEmpty(this.props.bindings)) {
91
+ // Do we want to save things on CPU side?
94
92
  Object.assign(this.props.bindings, bindings);
93
+
94
+ // Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
95
+ this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
96
+
95
97
  // Set up the bindings
96
98
  this._bindGroup = getBindGroup(
97
99
  this.device.handle,
@@ -118,7 +120,9 @@ export class WebGPURenderPipeline extends RenderPipeline {
118
120
  return this._bindGroup;
119
121
  }
120
122
 
121
- /** Populate the complex WebGPU GPURenderPipelineDescriptor */
123
+ /**
124
+ * Populate the complex WebGPU GPURenderPipelineDescriptor
125
+ */
122
126
  protected _getRenderPipelineDescriptor() {
123
127
  // Set up the vertex stage
124
128
  const vertex: GPUVertexState = {
@@ -203,8 +207,7 @@ export class WebGPURenderPipeline extends RenderPipeline {
203
207
  } else {
204
208
  webgpuRenderPass.handle.draw(
205
209
  options.vertexCount || 0,
206
- options.instanceCount,
207
- options.firstIndex,
210
+ options.instanceCount || 1, // If 0, nothing will be drawn
208
211
  options.firstInstance
209
212
  );
210
213
  }
@@ -47,7 +47,7 @@ export class WebGPUShader extends Shader {
47
47
 
48
48
  let language = this.props.language;
49
49
  // Compile from src
50
- if (!language) {
50
+ if (language === 'auto') {
51
51
  // wgsl uses C++ "auto" style arrow notation
52
52
  language = source.includes('->') ? 'wgsl' : 'glsl';
53
53
  }
@@ -45,6 +45,13 @@ export class WebGPUTexture extends Texture {
45
45
 
46
46
  this.width = this.handle.width;
47
47
  this.height = this.handle.height;
48
+ // Why not just read all properties directly from the texture
49
+ // this.depthOrArrayLayers = this.handle.depthOrArrayLayers;
50
+ // this.mipLevelCount = this.handle.mipLevelCount;
51
+ // this.sampleCount = this.handle.sampleCount;
52
+ // this.dimension = this.handle.dimension;
53
+ // this.format = this.handle.format;
54
+ // this.usage = this.handle.usage;
48
55
 
49
56
  // Create a default sampler. This mimics the WebGL1 API where sampler props are stored on the texture
50
57
  // this.setSampler(props.sampler);
@@ -0,0 +1,73 @@
1
+ // luma.gl, MIT license
2
+
3
+ import type {Device, Buffer, VertexArrayProps, RenderPass, TypedArray} from '@luma.gl/core';
4
+ import {VertexArray, log} from '@luma.gl/core';
5
+ import {getBrowser} from '@probe.gl/env';
6
+
7
+ import {WebGPUDevice} from '../webgpu-device';
8
+ import {WebGPUBuffer} from '../resources/webgpu-buffer';
9
+
10
+ import {WebGPURenderPass} from './webgpu-render-pass';
11
+
12
+ /** VertexArrayObject wrapper */
13
+ export class WebGPUVertexArray extends VertexArray {
14
+ override get [Symbol.toStringTag](): string {
15
+ return 'WebGPUVertexArray';
16
+ }
17
+
18
+ readonly device: WebGPUDevice;
19
+ /** Vertex Array is a helper class under WebGPU */
20
+ readonly handle: never;
21
+
22
+ /** * Attribute 0 can not be disable on most desktop OpenGL based browsers */
23
+ static isConstantAttributeZeroSupported(device: Device): boolean {
24
+ return device.info.type === 'webgl2' || getBrowser() === 'Chrome';
25
+ }
26
+
27
+ // Create a VertexArray
28
+ constructor(device: WebGPUDevice, props?: VertexArrayProps) {
29
+ super(device, props);
30
+ this.device = device;
31
+ }
32
+
33
+ override destroy(): void {}
34
+
35
+ /**
36
+ * Set an elements buffer, for indexed rendering.
37
+ * Must be a Buffer bound to buffer with usage bit Buffer.INDEX set.
38
+ */
39
+ setIndexBuffer(buffer: Buffer | null): void {
40
+ // assert(!elementBuffer || elementBuffer.glTarget === GL.ELEMENT_ARRAY_BUFFER, ERR_ELEMENTS);
41
+ this.indexBuffer = buffer;
42
+ }
43
+
44
+ /** Set a location in vertex attributes array to a buffer, enables the location, sets divisor */
45
+ setBuffer(location: number, buffer: Buffer): void {
46
+ // Sanity check target
47
+ // if (buffer.glUsage === GL.ELEMENT_ARRAY_BUFFER) {
48
+ // throw new Error('Use setIndexBuffer');
49
+ // }
50
+
51
+ this.attributes[location] = buffer;
52
+ }
53
+
54
+ /** Set a location in vertex attributes array to a constant value, disables the location */
55
+ override setConstant(location: number, value: TypedArray): void {
56
+ log.warn(`${this.id} constant attributes not supported on WebGPU`)
57
+ }
58
+
59
+ override bindBeforeRender(renderPass: RenderPass, firstIndex?: number, indexCount?: number): void {
60
+ const webgpuRenderPass = renderPass as WebGPURenderPass;
61
+ const webgpuIndexBuffer = this.indexBuffer as WebGPUBuffer;
62
+ webgpuRenderPass.handle.setIndexBuffer(webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType);
63
+ for (let location = 0; location < this.maxVertexAttributes; location++) {
64
+ const webgpuBuffer = this.attributes[location] as WebGPUBuffer;
65
+ webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer.handle);
66
+ }
67
+ // TODO - emit warnings/errors/throw if constants have been set on this vertex array
68
+ }
69
+
70
+ override unbindAfterRender(renderPass: RenderPass): void {
71
+ // On WebGPU we don't unbind
72
+ }
73
+ }
@@ -1,18 +1,23 @@
1
+ // / <reference types="@webgpu/types" />
1
2
  import type {Texture, TextureFormat, CanvasContextProps} from '@luma.gl/core';
2
3
  import {CanvasContext, log} from '@luma.gl/core';
3
4
  import {getWebGPUTextureFormat} from './helpers/convert-texture-format';
4
5
  import {WebGPUDevice} from './webgpu-device';
5
6
  import {WebGPUFramebuffer} from './resources/webgpu-framebuffer';
7
+ import {WebGPUTexture} from './resources/webgpu-texture';
6
8
 
7
9
  /**
8
- * Holds a WebGPU Canvas Context which handles resizing etc
10
+ * Holds a WebGPU Canvas Context
11
+ * The primary job of the CanvasContext is to generate textures for rendering into the current canvas
12
+ * It also manages canvas sizing calculations and resizing.
9
13
  */
10
14
  export class WebGPUCanvasContext extends CanvasContext {
11
15
  readonly device: WebGPUDevice;
12
16
  readonly gpuCanvasContext: GPUCanvasContext;
13
- readonly format: TextureFormat;
17
+ /** Format of returned textures: "bgra8unorm", "rgba8unorm", "rgba16float". */
18
+ readonly format: TextureFormat = navigator.gpu.getPreferredCanvasFormat();
19
+ /** Default stencil format for depth textures */
14
20
  depthStencilFormat: TextureFormat = 'depth24plus';
15
- sampleCount: number = 1;
16
21
 
17
22
  private depthStencilAttachment: Texture | null = null;
18
23
 
@@ -22,31 +27,46 @@ export class WebGPUCanvasContext extends CanvasContext {
22
27
  // TODO - hack to trigger resize?
23
28
  this.width = -1;
24
29
  this.height = -1;
25
-
30
+
26
31
  this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
27
32
  // @ts-ignore TODO - we don't handle OffscreenRenderingContext.
28
- this.gpuCanvasContext = this.canvas.getContext('webgpu') ;
29
- // @ts-expect-error TODO this has been replaced
30
- this.format = this.gpuCanvasContext.getPreferredFormat(adapter);
33
+ this.gpuCanvasContext = this.canvas.getContext('webgpu');
34
+ // TODO this has been replaced
35
+ // this.format = this.gpuCanvasContext.getPreferredFormat(adapter);
36
+ this.format = 'bgra8unorm';
31
37
  }
32
38
 
39
+ /** Destroy any textures produced while configured and remove the context configuration. */
33
40
  destroy(): void {
34
41
  this.gpuCanvasContext.unconfigure();
35
42
  }
36
43
 
44
+ getCurrentTexture(): WebGPUTexture {
45
+ // Wrap the current canvas context texture in a luma.gl texture
46
+ return this.device._createTexture({
47
+ id: 'default-render-target',
48
+ handle: this.gpuCanvasContext.getCurrentTexture()
49
+ });
50
+ }
51
+
37
52
  /** Update framebuffer with properly resized "swap chain" texture views */
38
53
  getCurrentFramebuffer(): WebGPUFramebuffer {
39
54
  // Ensure the canvas context size is updated
40
55
  this.update();
41
56
 
57
+ // Wrap the current canvas context texture in a luma.gl texture
58
+ // const currentColorAttachment = this.device.createTexture({
59
+ // id: 'default-render-target',
60
+ // handle: this.gpuCanvasContext.getCurrentTexture(),
61
+ // format: this.format,
62
+ // width: this.width,
63
+ // height: this.height
64
+ // });
65
+
42
66
  // Wrap the current canvas context texture in a luma.gl texture
43
- const currentColorAttachment = this.device.createTexture({
44
- id: 'default-render-target',
45
- handle: this.gpuCanvasContext.getCurrentTexture(),
46
- format: this.format,
47
- width: this.width,
48
- height: this.height
49
- });
67
+ const currentColorAttachment = this.getCurrentTexture();
68
+ this.width = currentColorAttachment.width;
69
+ this.height = currentColorAttachment.height;
50
70
 
51
71
  // Resize the depth stencil attachment
52
72
  this._createDepthStencilAttachment();
@@ -77,14 +97,14 @@ export class WebGPUCanvasContext extends CanvasContext {
77
97
  this.gpuCanvasContext.configure({
78
98
  device: this.device.handle,
79
99
  format: getWebGPUTextureFormat(this.format),
80
- // size: [this.width, this.height],
100
+ // Can be used to define e.g. -srgb views
101
+ // viewFormats: [...]
81
102
  colorSpace: this.props.colorSpace,
82
103
  alphaMode: this.props.alphaMode
83
104
  });
84
105
 
85
106
  log.log(1, `Resized to ${this.width}x${this.height}px`)();
86
107
  }
87
-
88
108
  }
89
109
 
90
110
  resize(options?: {width?: number; height?: number; useDevicePixels?: boolean | number}): void {
@@ -19,7 +19,8 @@ import type {
19
19
  ComputePipelineProps,
20
20
  RenderPassProps,
21
21
  ComputePassProps,
22
- // CommandEncoderProps
22
+ // CommandEncoderProps,
23
+ VertexArrayProps
23
24
  } from '@luma.gl/core';
24
25
  import {Device, CanvasContext, log, uid} from '@luma.gl/core';
25
26
  import {WebGPUBuffer} from './resources/webgpu-buffer';
@@ -33,6 +34,7 @@ import {WebGPUComputePipeline} from './resources/webgpu-compute-pipeline';
33
34
  import {WebGPURenderPass} from './resources/webgpu-render-pass';
34
35
  import {WebGPUComputePass} from './resources/webgpu-compute-pass';
35
36
  // import {WebGPUCommandEncoder} from './resources/webgpu-command-encoder';
37
+ import {WebGPUVertexArray} from './resources/webgpu-vertex-array';
36
38
 
37
39
  import {WebGPUCanvasContext} from './webgpu-canvas-context';
38
40
  // import {loadGlslangModule} from '../glsl/glslang';
@@ -105,7 +107,7 @@ export class WebGPUDevice extends Device {
105
107
  renderer: '',
106
108
  version: '',
107
109
  gpu: 'unknown', // 'nvidia' | 'amd' | 'intel' | 'apple' | 'unknown',
108
- shadingLanguages: ['glsl', 'wgsl'],
110
+ shadingLanguages: ['wgsl'],
109
111
  shadingLanguageVersions: {
110
112
  glsl: '450',
111
113
  wgsl: '100'
@@ -122,9 +124,9 @@ export class WebGPUDevice extends Device {
122
124
  });
123
125
 
124
126
  // Note: WebGPU devices can be created without a canvas, for compute shader purposes
125
- if (props.canvas) {
126
- this.canvasContext = new WebGPUCanvasContext(this, this.adapter, {canvas: props.canvas});
127
- }
127
+ // if (props.canvas) {
128
+ this.canvasContext = new WebGPUCanvasContext(this, this.adapter, {canvas: props.canvas});
129
+ // }
128
130
 
129
131
  this.features = this._getFeatures();
130
132
  }
@@ -199,6 +201,10 @@ export class WebGPUDevice extends Device {
199
201
  return new WebGPUComputePipeline(this, props);
200
202
  }
201
203
 
204
+ createVertexArray(props: VertexArrayProps): WebGPUVertexArray {
205
+ return new WebGPUVertexArray(this, props);
206
+ }
207
+
202
208
  // WebGPU specifics
203
209
 
204
210
  /**
@@ -227,24 +233,26 @@ export class WebGPUDevice extends Device {
227
233
  * Gets default renderpass encoder.
228
234
  * Creates a new encoder against default canvasContext if not already created
229
235
  * @note Called internally by Model.
236
+ * @deprecated Create explicit pass with device.beginRenderPass
230
237
  */
231
238
  getDefaultRenderPass(): WebGPURenderPass {
232
- this.renderPass =
233
- this.renderPass ||
234
- this.beginRenderPass({
235
- framebuffer: this.canvasContext?.getCurrentFramebuffer()
236
- });
237
- return this.renderPass;
239
+ // this.renderPass =
240
+ // this.renderPass ||
241
+ // this.beginRenderPass({
242
+ // framebuffer: this.canvasContext?.getCurrentFramebuffer()
243
+ // });
244
+ // return this.renderPass;
245
+ throw new Error('a');
238
246
  }
239
247
 
240
248
  submit(): void {
241
- this.renderPass?.end();
249
+ // this.renderPass?.end();
242
250
  const commandBuffer = this.commandEncoder?.finish();
243
251
  if (commandBuffer) {
244
252
  this.handle.queue.submit([commandBuffer]);
245
253
  }
246
254
  this.commandEncoder = null;
247
- this.renderPass = null;
255
+ // this.renderPass = null;
248
256
  }
249
257
 
250
258
  _getFeatures() {