@luma.gl/webgpu 9.0.0-alpha.4 → 9.0.0-alpha.40

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 (121) hide show
  1. package/LICENSE +3 -1
  2. package/dist/adapter/helpers/accessor-to-format.js.map +1 -1
  3. package/dist/adapter/helpers/convert-texture-format.d.ts +2 -2
  4. package/dist/adapter/helpers/convert-texture-format.d.ts.map +1 -1
  5. package/dist/adapter/helpers/convert-texture-format.js +0 -1
  6. package/dist/adapter/helpers/convert-texture-format.js.map +1 -1
  7. package/dist/adapter/helpers/generate-mipmaps.d.ts +1 -1
  8. package/dist/adapter/helpers/generate-mipmaps.js +19 -14
  9. package/dist/adapter/helpers/generate-mipmaps.js.map +1 -1
  10. package/dist/adapter/helpers/get-bind-group.d.ts +4 -4
  11. package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
  12. package/dist/adapter/helpers/get-bind-group.js +8 -17
  13. package/dist/adapter/helpers/get-bind-group.js.map +1 -1
  14. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts +5 -5
  15. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
  16. package/dist/adapter/helpers/get-vertex-buffer-layout.js +33 -40
  17. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -1
  18. package/dist/adapter/helpers/webgpu-parameters.d.ts +2 -2
  19. package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -1
  20. package/dist/adapter/helpers/webgpu-parameters.js +51 -48
  21. package/dist/adapter/helpers/webgpu-parameters.js.map +1 -1
  22. package/dist/adapter/resources/webgpu-buffer.d.ts +4 -5
  23. package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
  24. package/dist/adapter/resources/webgpu-buffer.js +16 -31
  25. package/dist/adapter/resources/webgpu-buffer.js.map +1 -1
  26. package/dist/adapter/resources/webgpu-command-encoder.d.ts +6 -15
  27. package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
  28. package/dist/adapter/resources/webgpu-command-encoder.js +11 -29
  29. package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -1
  30. package/dist/adapter/resources/webgpu-compute-pass.d.ts +6 -6
  31. package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
  32. package/dist/adapter/resources/webgpu-compute-pass.js +14 -27
  33. package/dist/adapter/resources/webgpu-compute-pass.js.map +1 -1
  34. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +4 -4
  35. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
  36. package/dist/adapter/resources/webgpu-compute-pipeline.js +6 -11
  37. package/dist/adapter/resources/webgpu-compute-pipeline.js.map +1 -1
  38. package/dist/adapter/resources/webgpu-external-texture.d.ts +5 -5
  39. package/dist/adapter/resources/webgpu-external-texture.d.ts.map +1 -1
  40. package/dist/adapter/resources/webgpu-external-texture.js +6 -14
  41. package/dist/adapter/resources/webgpu-external-texture.js.map +1 -1
  42. package/dist/adapter/resources/webgpu-framebuffer.d.ts +4 -21
  43. package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -1
  44. package/dist/adapter/resources/webgpu-framebuffer.js +4 -105
  45. package/dist/adapter/resources/webgpu-framebuffer.js.map +1 -1
  46. package/dist/adapter/resources/webgpu-query.js.map +1 -1
  47. package/dist/adapter/resources/webgpu-render-pass.d.ts +12 -7
  48. package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
  49. package/dist/adapter/resources/webgpu-render-pass.js +59 -36
  50. package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
  51. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +14 -10
  52. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  53. package/dist/adapter/resources/webgpu-render-pipeline.js +50 -67
  54. package/dist/adapter/resources/webgpu-render-pipeline.js.map +1 -1
  55. package/dist/adapter/resources/webgpu-sampler.d.ts +5 -5
  56. package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -1
  57. package/dist/adapter/resources/webgpu-sampler.js +11 -11
  58. package/dist/adapter/resources/webgpu-sampler.js.map +1 -1
  59. package/dist/adapter/resources/webgpu-shader.d.ts +7 -7
  60. package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
  61. package/dist/adapter/resources/webgpu-shader.js +11 -25
  62. package/dist/adapter/resources/webgpu-shader.js.map +1 -1
  63. package/dist/adapter/resources/webgpu-texture.d.ts +15 -8
  64. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  65. package/dist/adapter/resources/webgpu-texture.js +17 -27
  66. package/dist/adapter/resources/webgpu-texture.js.map +1 -1
  67. package/dist/adapter/resources/webgpu-vertex-array.d.ts +26 -0
  68. package/dist/adapter/resources/webgpu-vertex-array.d.ts.map +1 -0
  69. package/dist/adapter/resources/webgpu-vertex-array.js +39 -0
  70. package/dist/adapter/resources/webgpu-vertex-array.js.map +1 -0
  71. package/dist/adapter/webgpu-canvas-context.d.ts +16 -12
  72. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
  73. package/dist/adapter/webgpu-canvas-context.js +26 -47
  74. package/dist/adapter/webgpu-canvas-context.js.map +1 -1
  75. package/dist/adapter/webgpu-device.d.ts +38 -22
  76. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  77. package/dist/adapter/webgpu-device.js +87 -91
  78. package/dist/adapter/webgpu-device.js.map +1 -1
  79. package/dist/adapter/webgpu-types.js.map +1 -1
  80. package/dist/dist.dev.js +3586 -0
  81. package/dist/glsl/glsllang.js +0 -1
  82. package/dist/glsl/glsllang.js.map +1 -1
  83. package/dist/index.cjs +1519 -0
  84. package/dist/index.d.ts +5 -7
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +5 -7
  87. package/dist/index.js.map +1 -1
  88. package/dist.min.js +18 -0
  89. package/package.json +18 -9
  90. package/src/adapter/helpers/accessor-to-format.ts +2 -2
  91. package/src/adapter/helpers/convert-texture-format.ts +1 -1
  92. package/src/adapter/helpers/generate-mipmaps.ts +1 -1
  93. package/src/adapter/helpers/get-bind-group.ts +22 -12
  94. package/src/adapter/helpers/get-vertex-buffer-layout.ts +58 -34
  95. package/src/adapter/helpers/webgpu-parameters.ts +56 -47
  96. package/src/adapter/resources/webgpu-buffer.ts +6 -10
  97. package/src/adapter/resources/webgpu-command-encoder.ts +62 -41
  98. package/src/adapter/resources/webgpu-compute-pass.ts +13 -13
  99. package/src/adapter/resources/webgpu-compute-pipeline.ts +6 -5
  100. package/src/adapter/resources/webgpu-external-texture.ts +5 -5
  101. package/src/adapter/resources/webgpu-framebuffer.ts +8 -109
  102. package/src/adapter/resources/webgpu-query.ts +3 -3
  103. package/src/adapter/resources/webgpu-render-pass.ts +74 -18
  104. package/src/adapter/resources/webgpu-render-pipeline.ts +64 -39
  105. package/src/adapter/resources/webgpu-sampler.ts +12 -5
  106. package/src/adapter/resources/webgpu-shader.ts +13 -10
  107. package/src/adapter/resources/webgpu-texture.ts +22 -8
  108. package/src/adapter/resources/webgpu-vertex-array.ts +74 -0
  109. package/src/adapter/webgpu-canvas-context.ts +52 -27
  110. package/src/adapter/webgpu-device.ts +150 -60
  111. package/src/index.ts +7 -9
  112. package/dist/bundle.d.ts +0 -2
  113. package/dist/bundle.d.ts.map +0 -1
  114. package/dist/bundle.js +0 -5
  115. package/dist/bundle.js.map +0 -1
  116. package/dist/init.d.ts +0 -2
  117. package/dist/init.d.ts.map +0 -1
  118. package/dist/init.js +0 -4
  119. package/dist/init.js.map +0 -1
  120. package/src/bundle.ts +0 -4
  121. package/src/init.ts +0 -4
@@ -1,11 +1,12 @@
1
- import type {RenderPassProps, RenderPassParameters, Binding} from '@luma.gl/api';
2
- import {Buffer, RenderPass, RenderPipeline, cast, log} from '@luma.gl/api';
3
- import WebGPUDevice from '../webgpu-device';
4
- import WebGPUBuffer from './webgpu-buffer';
5
- // import WebGPUCommandEncoder from './webgpu-command-encoder';
6
- import WebGPURenderPipeline from './webgpu-render-pipeline';
7
-
8
- export default class WebGPURenderPass extends RenderPass {
1
+ import type {RenderPassProps, RenderPassParameters, Binding, Framebuffer} from '@luma.gl/core';
2
+ import {Buffer, RenderPass, RenderPipeline, cast, log} from '@luma.gl/core';
3
+ import {WebGPUDevice} from '../webgpu-device';
4
+ import {WebGPUBuffer} from './webgpu-buffer';
5
+ import {WebGPUTexture} from './webgpu-texture';
6
+ // import {WebGPUCommandEncoder} from './webgpu-command-encoder';
7
+ import {WebGPURenderPipeline} from './webgpu-render-pipeline';
8
+
9
+ export class WebGPURenderPass extends RenderPass {
9
10
  readonly device: WebGPUDevice;
10
11
  readonly handle: GPURenderPassEncoder;
11
12
 
@@ -15,17 +16,19 @@ export default class WebGPURenderPass extends RenderPass {
15
16
  constructor(device: WebGPUDevice, props: RenderPassProps = {}) {
16
17
  super(device, props);
17
18
  this.device = device;
18
- const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer();
19
- // @ts-expect-error
20
- const renderPassDescriptor = framebuffer.renderPassDescriptor;
19
+ const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer() ;
20
+ const renderPassDescriptor = this.getRenderPassDescriptor(framebuffer);
21
+ log.groupCollapsed(1, `new WebGPURenderPass(${this.id})`)();
22
+ log.probe(1, JSON.stringify(renderPassDescriptor, null, 2))();
23
+ log.groupEnd(1)();
21
24
  this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
22
25
  this.handle.label = this.props.id;
23
26
  }
24
27
 
25
- destroy() {}
28
+ override destroy(): void {}
26
29
 
27
- endPass(): void {
28
- this.handle.endPass();
30
+ end(): void {
31
+ this.handle.end();
29
32
  }
30
33
 
31
34
  setPipeline(pipeline: RenderPipeline): void {
@@ -35,8 +38,11 @@ export default class WebGPURenderPass extends RenderPass {
35
38
 
36
39
  /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
37
40
  setBindings(bindings: Record<string, Binding>): void {
38
- this.pipeline.setBindings(bindings);
39
- this.handle.setBindGroup(0, this.pipeline._getBindGroup());
41
+ this.pipeline?.setBindings(bindings);
42
+ const bindGroup = this.pipeline?._getBindGroup();
43
+ if (bindGroup) {
44
+ this.handle.setBindGroup(0, bindGroup);
45
+ }
40
46
  }
41
47
 
42
48
  setIndexBuffer(
@@ -71,8 +77,8 @@ export default class WebGPURenderPass extends RenderPass {
71
77
  );
72
78
  } else {
73
79
  this.handle.draw(
74
- options.vertexCount,
75
- options.instanceCount,
80
+ options.vertexCount || 0,
81
+ options.instanceCount || 1,
76
82
  options.firstIndex,
77
83
  options.firstInstance
78
84
  );
@@ -125,4 +131,54 @@ export default class WebGPURenderPass extends RenderPass {
125
131
  // endPipelineStatisticsQuery(querySet: GPUQuerySet, queryIndex: number): void;
126
132
 
127
133
  // executeBundles(bundles: Iterable<GPURenderBundle>): void;
134
+
135
+ // INTERNAL
136
+
137
+ /**
138
+ * Partial render pass descriptor. Used by WebGPURenderPass.
139
+ * @returns attachments fields of a renderpass descriptor.
140
+ */
141
+ protected getRenderPassDescriptor(framebuffer: Framebuffer): GPURenderPassDescriptor {
142
+ const renderPassDescriptor: GPURenderPassDescriptor = {
143
+ colorAttachments: []
144
+ };
145
+
146
+ renderPassDescriptor.colorAttachments = framebuffer.colorAttachments.map(colorAttachment => ({
147
+ // clear values
148
+ loadOp: this.props.clearColor !== false ? 'clear' : 'load',
149
+ colorClearValue: this.props.clearColor || [0, 0, 0, 0],
150
+ storeOp: this.props.discard? 'discard': 'store',
151
+ // ...colorAttachment,
152
+ view: (colorAttachment as WebGPUTexture).handle.createView()
153
+ }));
154
+
155
+ if (framebuffer.depthStencilAttachment) {
156
+ renderPassDescriptor.depthStencilAttachment = {
157
+ view: (framebuffer.depthStencilAttachment as WebGPUTexture).handle.createView()
158
+ };
159
+ const {depthStencilAttachment} = renderPassDescriptor;
160
+
161
+ // DEPTH
162
+ if (this.props.depthReadOnly) {
163
+ depthStencilAttachment.depthReadOnly = true;
164
+ }
165
+ depthStencilAttachment.depthClearValue = this.props.clearDepth || 0;
166
+
167
+ // WebGPU only wants us to set these parameters if the texture format actually has a depth aspect
168
+ const hasDepthAspect = true;
169
+ if (hasDepthAspect) {
170
+ depthStencilAttachment.depthLoadOp = this.props.clearDepth !== false ? 'clear' : 'load';
171
+ depthStencilAttachment.depthStoreOp = 'store'; // TODO - support 'discard'?
172
+ }
173
+
174
+ // WebGPU only wants us to set these parameters if the texture format actually has a stencil aspect
175
+ const hasStencilAspect = false;
176
+ if (hasStencilAspect) {
177
+ depthStencilAttachment.stencilLoadOp = this.props.clearStencil !== false ? 'clear' : 'load';
178
+ depthStencilAttachment.stencilStoreOp = 'store'; // TODO - support 'discard'?
179
+ }
180
+ }
181
+
182
+ return renderPassDescriptor;
183
+ }
128
184
  }
@@ -1,5 +1,7 @@
1
- import type {Binding, RenderPass} from '@luma.gl/api';
2
- import {Buffer, RenderPipeline, RenderPipelineProps, cast, log, isObjectEmpty} from '@luma.gl/api';
1
+ // luma.gl MIT license
2
+
3
+ import type {TypedArray, Binding, UniformValue, RenderPass} from '@luma.gl/core';
4
+ import {Buffer, RenderPipeline, RenderPipelineProps, cast, log, isObjectEmpty} 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';
@@ -8,49 +10,52 @@ import {getVertexBufferLayout, getBufferSlots} from '../helpers/get-vertex-buffe
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 default class WebGPURenderPipeline extends RenderPipeline {
21
+ export class WebGPURenderPipeline extends RenderPipeline {
20
22
  device: WebGPUDevice;
21
23
  handle: GPURenderPipeline;
22
24
 
25
+ vs: WebGPUShader;
26
+ fs: WebGPUShader | null = null;
27
+
23
28
  private _bufferSlots: Record<string, number>;
24
29
  private _buffers: Buffer[];
25
- private _indexBuffer: WebGPUBuffer;
30
+ private _indexBuffer: WebGPUBuffer | null = null;
26
31
  // private _firstIndex: number;
27
32
  // private _lastIndex: number;
28
33
 
29
34
  /** For internal use to create BindGroups */
30
- private _bindGroupLayout: GPUBindGroupLayout;
31
- private _bindGroup: GPUBindGroup = null;
35
+ private _bindGroupLayout: GPUBindGroupLayout | null = null;
36
+ private _bindGroup: GPUBindGroup | null = null;
32
37
 
33
38
  constructor(device: WebGPUDevice, props: RenderPipelineProps) {
34
39
  super(device, props);
35
40
  this.device = device;
36
- 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
+ }
37
49
  this.handle.label = this.props.id;
38
50
 
39
- this._bufferSlots = getBufferSlots(this.props.layout, this.props.bufferMap);
40
- this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
41
- this._bindGroupLayout = this.handle.getBindGroupLayout(0);
42
- }
51
+ this.vs = cast<WebGPUShader>(props.vs);
52
+ this.fs = cast<WebGPUShader>(props.fs);
43
53
 
44
- protected createHandle(): GPURenderPipeline {
45
- const descriptor = this._getRenderPipelineDescriptor();
46
- const renderPipeline = this.device.handle.createRenderPipeline(descriptor);
47
- log.groupCollapsed(1, `new WebGPRenderPipeline(${this.id})`)();
48
- log.log(1, JSON.stringify(descriptor, null, 2))();
49
- log.groupEnd(1)();
50
- return renderPipeline;
54
+ this._bufferSlots = getBufferSlots(this.props.shaderLayout, this.props.bufferLayout);
55
+ this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
51
56
  }
52
57
 
53
- destroy() {
58
+ override destroy(): void {
54
59
  // WebGPURenderPipeline has no destroy method.
55
60
  }
56
61
 
@@ -77,21 +82,29 @@ export default class WebGPURenderPipeline extends RenderPipeline {
77
82
  // }
78
83
  }
79
84
 
80
- /** Set the bindings */
85
+ setConstantAttributes(attributes: Record<string, TypedArray>): void {
86
+ throw new Error('not implemented');
87
+ }
88
+
81
89
  setBindings(bindings: Record<string, Binding>): void {
82
90
  if (!isObjectEmpty(this.props.bindings)) {
91
+ // Do we want to save things on CPU side?
83
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
+
84
97
  // Set up the bindings
85
98
  this._bindGroup = getBindGroup(
86
99
  this.device.handle,
87
100
  this._bindGroupLayout,
88
- this.props.layout,
101
+ this.props.shaderLayout,
89
102
  this.props.bindings
90
103
  );
91
104
  }
92
105
  }
93
106
 
94
- setUniforms(uniforms: Record<string, any>): void {
107
+ setUniforms(uniforms: Record<string, UniformValue>): void {
95
108
  if (!isObjectEmpty(uniforms)) {
96
109
  throw new Error('WebGPU does not support uniforms');
97
110
  }
@@ -107,13 +120,15 @@ export default class WebGPURenderPipeline extends RenderPipeline {
107
120
  return this._bindGroup;
108
121
  }
109
122
 
110
- /** Populate the complex WebGPU GPURenderPipelineDescriptor */
123
+ /**
124
+ * Populate the complex WebGPU GPURenderPipelineDescriptor
125
+ */
111
126
  protected _getRenderPipelineDescriptor() {
112
127
  // Set up the vertex stage
113
128
  const vertex: GPUVertexState = {
114
129
  module: cast<WebGPUShader>(this.props.vs).handle,
115
130
  entryPoint: this.props.vsEntryPoint || 'main',
116
- buffers: getVertexBufferLayout(this.props.layout, this.props.bufferMap)
131
+ buffers: getVertexBufferLayout(this.props.shaderLayout, this.props.bufferLayout)
117
132
  };
118
133
 
119
134
  // Set up the fragment stage
@@ -124,19 +139,29 @@ export default class WebGPURenderPipeline extends RenderPipeline {
124
139
  entryPoint: this.props.fsEntryPoint || 'main',
125
140
  targets: [
126
141
  {
127
- format: getWebGPUTextureFormat(this.device.canvasContext.format)
142
+ // TODO exclamation mark hack!
143
+ format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
128
144
  }
129
145
  ]
130
146
  };
131
147
  }
132
148
 
149
+ // WebGPU has more restrictive topology support than WebGL
150
+ switch (this.props.topology) {
151
+ case 'triangle-fan-webgl':
152
+ case 'line-loop-webgl':
153
+ throw new Error(`WebGPU does not support primitive topology ${this.props.topology}`);
154
+ default:
155
+ }
156
+
133
157
  // Create a partially populated descriptor
134
- let descriptor: GPURenderPipelineDescriptor = {
158
+ const descriptor: GPURenderPipelineDescriptor = {
135
159
  vertex,
136
160
  fragment,
137
161
  primitive: {
138
162
  topology: this.props.topology
139
- }
163
+ },
164
+ layout: 'auto'
140
165
  };
141
166
 
142
167
  // Set parameters on the descriptor
@@ -155,15 +180,16 @@ export default class WebGPURenderPipeline extends RenderPipeline {
155
180
  firstInstance?: number;
156
181
  baseVertex?: number;
157
182
  }): void {
158
- const webgpuRenderPass =
183
+ const webgpuRenderPass: WebGPURenderPass =
159
184
  cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
160
185
 
161
186
  // Set pipeline
162
187
  webgpuRenderPass.handle.setPipeline(this.handle);
163
188
 
164
189
  // Set bindings (uniform buffers, textures etc)
165
- if (this._getBindGroup()) {
166
- webgpuRenderPass.handle.setBindGroup(0, this._getBindGroup());
190
+ const bindGroup = this._getBindGroup();
191
+ if (bindGroup) {
192
+ webgpuRenderPass.handle.setBindGroup(0, bindGroup);
167
193
  }
168
194
 
169
195
  // Set attributes
@@ -180,9 +206,8 @@ export default class WebGPURenderPipeline extends RenderPipeline {
180
206
  );
181
207
  } else {
182
208
  webgpuRenderPass.handle.draw(
183
- options.vertexCount,
184
- options.instanceCount,
185
- options.firstIndex,
209
+ options.vertexCount || 0,
210
+ options.instanceCount || 1, // If 0, nothing will be drawn
186
211
  options.firstInstance
187
212
  );
188
213
  }
@@ -197,7 +222,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
197
222
  for (let i = 0; i < buffers.length; ++i) {
198
223
  const buffer = cast<WebGPUBuffer>(buffers[i]);
199
224
  if (!buffer) {
200
- const attribute = this.props.layout.attributes.find(
225
+ const attribute = this.props.shaderLayout.attributes.find(
201
226
  (attribute) => attribute.location === i
202
227
  );
203
228
  throw new Error(
@@ -209,7 +234,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
209
234
 
210
235
  // TODO - HANDLE buffer maps
211
236
  /*
212
- for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferMap)) {
237
+ for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
213
238
  const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
214
239
  if (!buffer) {
215
240
  log.warn(`Missing buffer for buffer map ${bufferName}`)();
@@ -1,5 +1,5 @@
1
- import {Sampler, SamplerProps} from '@luma.gl/api';
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;
@@ -8,18 +8,25 @@ export type WebGPUSamplerProps = SamplerProps & {
8
8
  /**
9
9
  *
10
10
  */
11
- export default class WebGPUSampler extends Sampler {
11
+ export class WebGPUSampler extends Sampler {
12
12
  readonly device: WebGPUDevice;
13
13
  readonly handle: GPUSampler;
14
14
 
15
15
  constructor(device: WebGPUDevice, props: WebGPUSamplerProps) {
16
16
  super(device, props);
17
17
  this.device = device;
18
- this.handle = this.handle || this.device.handle.createSampler(this.props);
18
+
19
+ // Prepare sampler props
20
+ const samplerProps: Partial<WebGPUSamplerProps> = {...this.props};
21
+ if (samplerProps.type !== 'comparison-sampler') {
22
+ delete samplerProps.compare;
23
+ }
24
+
25
+ this.handle = this.handle || this.device.handle.createSampler(samplerProps);
19
26
  this.handle.label = this.props.id;
20
27
  }
21
28
 
22
- destroy(): void {
29
+ override destroy(): void {
23
30
  // this.handle.destroy();
24
31
  }
25
32
  }
@@ -1,6 +1,9 @@
1
- import type {ShaderProps, CompilerMessage} from '@luma.gl/api';
2
- import {Shader, log} from '@luma.gl/api';
3
- import type WebGPUDevice from '../webgpu-device';
1
+ // luma.gl, MIT license
2
+ // Copyright (c) vis.gl contributors
3
+
4
+ import type {ShaderProps, CompilerMessage} from '@luma.gl/core';
5
+ import {Shader, log} from '@luma.gl/core';
6
+ import type {WebGPUDevice} from '../webgpu-device';
4
7
 
5
8
  export type WebGPUShaderProps = ShaderProps & {
6
9
  handle?: GPUShaderModule;
@@ -9,7 +12,7 @@ export type WebGPUShaderProps = ShaderProps & {
9
12
  /**
10
13
  * Immutable shader
11
14
  */
12
- export default class WebGPUShader extends Shader {
15
+ export class WebGPUShader extends Shader {
13
16
  readonly device: WebGPUDevice;
14
17
  readonly handle: GPUShaderModule;
15
18
 
@@ -25,7 +28,7 @@ export default class WebGPUShader extends Shader {
25
28
  this._checkCompilationError(this.device.handle.popErrorScope());
26
29
  }
27
30
 
28
- async _checkCompilationError(errorScope: Promise<GPUError>): Promise<void> {
31
+ async _checkCompilationError(errorScope: Promise<GPUError | null>): Promise<void> {
29
32
  const error = await errorScope as GPUValidationError;
30
33
  if (error) {
31
34
  const shaderLog = await this.compilationInfo();
@@ -36,16 +39,16 @@ export default class WebGPUShader extends Shader {
36
39
  }
37
40
  }
38
41
 
39
- destroy() {
42
+ override destroy(): void {
40
43
  // this.handle.destroy();
41
44
  }
42
45
 
43
46
  protected createHandle(): GPUShaderModule {
44
- const {source} = this.props;
47
+ const {source, stage} = this.props;
45
48
 
46
49
  let language = this.props.language;
47
50
  // Compile from src
48
- if (!language) {
51
+ if (language === 'auto') {
49
52
  // wgsl uses C++ "auto" style arrow notation
50
53
  language = source.includes('->') ? 'wgsl' : 'glsl';
51
54
  }
@@ -57,7 +60,7 @@ export default class WebGPUShader extends Shader {
57
60
  return this.device.handle.createShaderModule({
58
61
  code: source,
59
62
  // @ts-expect-error
60
- transform: (glsl) => this.device.glslang.compileGLSL(glsl, type)
63
+ transform: (glsl) => this.device.glslang.compileGLSL(glsl, stage)
61
64
  });
62
65
  default:
63
66
  throw new Error(language);
@@ -66,7 +69,7 @@ export default class WebGPUShader extends Shader {
66
69
 
67
70
  /** Returns compilation info for this shader */
68
71
  async compilationInfo(): Promise<readonly CompilerMessage[]> {
69
- const compilationInfo = await this.handle.compilationInfo();
72
+ const compilationInfo = await this.handle.getCompilationInfo();
70
73
  return compilationInfo.messages;
71
74
  }
72
75
  }
@@ -1,8 +1,8 @@
1
1
  // luma.gl, MIT license
2
- import {Texture, TextureProps, Sampler, SamplerProps, assert} from '@luma.gl/api';
2
+ import {Texture, TextureProps, Sampler, SamplerProps} from '@luma.gl/core';
3
3
  import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
4
- import type WebGPUDevice from '../webgpu-device';
5
- import WebGPUSampler from './webgpu-sampler';
4
+ import type {WebGPUDevice} from '../webgpu-device';
5
+ import {WebGPUSampler} from './webgpu-sampler';
6
6
 
7
7
  const BASE_DIMENSIONS: Record<string, '1d' | '2d' | '3d'> = {
8
8
  '1d': '1d',
@@ -13,12 +13,15 @@ const BASE_DIMENSIONS: Record<string, '1d' | '2d' | '3d'> = {
13
13
  '3d': '3d'
14
14
  };
15
15
 
16
- export default class WebGPUTexture extends Texture {
16
+ export class WebGPUTexture extends Texture {
17
17
  readonly device: WebGPUDevice;
18
18
  readonly handle: GPUTexture;
19
19
  readonly view: GPUTextureView;
20
20
  sampler: WebGPUSampler;
21
21
 
22
+ override height: number;
23
+ override width: number;
24
+
22
25
  // static async createFromImageURL(src, usage = 0) {
23
26
  // const img = document.createElement('img');
24
27
  // img.src = src;
@@ -40,8 +43,19 @@ export default class WebGPUTexture extends Texture {
40
43
  this.setData({data: this.props.data} );
41
44
  }
42
45
 
46
+ this.width = this.handle.width;
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;
55
+
43
56
  // Create a default sampler. This mimics the WebGL1 API where sampler props are stored on the texture
44
- this.setSampler(props.sampler);
57
+ // this.setSampler(props.sampler);
58
+ this.sampler = props.sampler instanceof WebGPUSampler ? props.sampler : new WebGPUSampler(this.device, props.sampler);
45
59
 
46
60
  // TODO - To support texture arrays we need to create custom views...
47
61
  // But we are not ready to expose TextureViews to the public API.
@@ -81,7 +95,7 @@ export default class WebGPUTexture extends Texture {
81
95
  });
82
96
  }
83
97
 
84
- destroy(): void {
98
+ override destroy(): void {
85
99
  this.handle.destroy();
86
100
  }
87
101
 
@@ -115,7 +129,7 @@ export default class WebGPUTexture extends Texture {
115
129
  aspect?: 'all' | 'stencil-only' | 'depth-only';
116
130
  colorSpace?: 'srgb';
117
131
  premultipliedAlpha?: boolean;
118
- }): this {
132
+ }): {width: number, height: number} {
119
133
  const {
120
134
  source,
121
135
  width = options.source.width,
@@ -156,7 +170,7 @@ export default class WebGPUTexture extends Texture {
156
170
  depth
157
171
  ]
158
172
  );
159
- return this;
173
+ return {width, height};
160
174
  }
161
175
 
162
176
  /*
@@ -0,0 +1,74 @@
1
+ // luma.gl, MIT license
2
+ // Copyright (c) vis.gl contributors
3
+
4
+ import type {Device, Buffer, VertexArrayProps, RenderPass, TypedArray} from '@luma.gl/core';
5
+ import {VertexArray, log} from '@luma.gl/core';
6
+ import {getBrowser} from '@probe.gl/env';
7
+
8
+ import {WebGPUDevice} from '../webgpu-device';
9
+ import {WebGPUBuffer} from '../resources/webgpu-buffer';
10
+
11
+ import {WebGPURenderPass} from './webgpu-render-pass';
12
+
13
+ /** VertexArrayObject wrapper */
14
+ export class WebGPUVertexArray extends VertexArray {
15
+ override get [Symbol.toStringTag](): string {
16
+ return 'WebGPUVertexArray';
17
+ }
18
+
19
+ readonly device: WebGPUDevice;
20
+ /** Vertex Array is a helper class under WebGPU */
21
+ readonly handle: never;
22
+
23
+ /** * Attribute 0 can not be disable on most desktop OpenGL based browsers */
24
+ static isConstantAttributeZeroSupported(device: Device): boolean {
25
+ return device.info.type === 'webgl2' || getBrowser() === 'Chrome';
26
+ }
27
+
28
+ // Create a VertexArray
29
+ constructor(device: WebGPUDevice, props?: VertexArrayProps) {
30
+ super(device, props);
31
+ this.device = device;
32
+ }
33
+
34
+ override destroy(): void {}
35
+
36
+ /**
37
+ * Set an elements buffer, for indexed rendering.
38
+ * Must be a Buffer bound to buffer with usage bit Buffer.INDEX set.
39
+ */
40
+ setIndexBuffer(buffer: Buffer | null): void {
41
+ // assert(!elementBuffer || elementBuffer.glTarget === GL.ELEMENT_ARRAY_BUFFER, ERR_ELEMENTS);
42
+ this.indexBuffer = buffer;
43
+ }
44
+
45
+ /** Set a location in vertex attributes array to a buffer, enables the location, sets divisor */
46
+ setBuffer(location: number, buffer: Buffer): void {
47
+ // Sanity check target
48
+ // if (buffer.glUsage === GL.ELEMENT_ARRAY_BUFFER) {
49
+ // throw new Error('Use setIndexBuffer');
50
+ // }
51
+
52
+ this.attributes[location] = buffer;
53
+ }
54
+
55
+ /** Set a location in vertex attributes array to a constant value, disables the location */
56
+ override setConstant(location: number, value: TypedArray): void {
57
+ log.warn(`${this.id} constant attributes not supported on WebGPU`)
58
+ }
59
+
60
+ override bindBeforeRender(renderPass: RenderPass, firstIndex?: number, indexCount?: number): void {
61
+ const webgpuRenderPass = renderPass as WebGPURenderPass;
62
+ const webgpuIndexBuffer = this.indexBuffer as WebGPUBuffer;
63
+ webgpuRenderPass.handle.setIndexBuffer(webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType);
64
+ for (let location = 0; location < this.maxVertexAttributes; location++) {
65
+ const webgpuBuffer = this.attributes[location] as WebGPUBuffer;
66
+ webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer.handle);
67
+ }
68
+ // TODO - emit warnings/errors/throw if constants have been set on this vertex array
69
+ }
70
+
71
+ override unbindAfterRender(renderPass: RenderPass): void {
72
+ // On WebGPU we don't unbind
73
+ }
74
+ }