@luma.gl/webgpu 9.0.0-alpha.9 → 9.0.0-beta.1

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 +20 -15
  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 +11 -18
  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 +36 -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 +14 -20
  21. package/dist/adapter/helpers/webgpu-parameters.js.map +1 -1
  22. package/dist/adapter/resources/webgpu-buffer.d.ts +14 -5
  23. package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
  24. package/dist/adapter/resources/webgpu-buffer.js +19 -29
  25. package/dist/adapter/resources/webgpu-buffer.js.map +1 -1
  26. package/dist/adapter/resources/webgpu-command-encoder.d.ts +7 -14
  27. package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
  28. package/dist/adapter/resources/webgpu-command-encoder.js +13 -27
  29. package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -1
  30. package/dist/adapter/resources/webgpu-compute-pass.d.ts +5 -5
  31. package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
  32. package/dist/adapter/resources/webgpu-compute-pass.js +13 -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 +8 -13
  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 +53 -36
  50. package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
  51. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +15 -22
  52. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  53. package/dist/adapter/resources/webgpu-render-pipeline.js +45 -115
  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 +8 -14
  58. package/dist/adapter/resources/webgpu-sampler.js.map +1 -1
  59. package/dist/adapter/resources/webgpu-shader.d.ts +9 -9
  60. package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
  61. package/dist/adapter/resources/webgpu-shader.js +15 -29
  62. package/dist/adapter/resources/webgpu-shader.js.map +1 -1
  63. package/dist/adapter/resources/webgpu-texture.d.ts +18 -8
  64. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  65. package/dist/adapter/resources/webgpu-texture.js +38 -33
  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 +45 -0
  70. package/dist/adapter/resources/webgpu-vertex-array.js.map +1 -0
  71. package/dist/adapter/webgpu-canvas-context.d.ts +17 -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 +34 -17
  76. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  77. package/dist/adapter/webgpu-device.js +94 -103
  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 +3130 -0
  81. package/dist/glsl/glsllang.js +0 -1
  82. package/dist/glsl/glsllang.js.map +1 -1
  83. package/dist/index.cjs +1551 -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 +30 -0
  89. package/package.json +18 -9
  90. package/src/adapter/helpers/accessor-to-format.ts +1 -2
  91. package/src/adapter/helpers/convert-texture-format.ts +1 -1
  92. package/src/adapter/helpers/generate-mipmaps.ts +2 -2
  93. package/src/adapter/helpers/get-bind-group.ts +23 -13
  94. package/src/adapter/helpers/get-vertex-buffer-layout.ts +61 -35
  95. package/src/adapter/helpers/webgpu-parameters.ts +20 -14
  96. package/src/adapter/resources/webgpu-buffer.ts +63 -8
  97. package/src/adapter/resources/webgpu-command-encoder.ts +68 -48
  98. package/src/adapter/resources/webgpu-compute-pass.ts +13 -12
  99. package/src/adapter/resources/webgpu-compute-pipeline.ts +8 -7
  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 +68 -15
  104. package/src/adapter/resources/webgpu-render-pipeline.ts +106 -87
  105. package/src/adapter/resources/webgpu-sampler.ts +6 -6
  106. package/src/adapter/resources/webgpu-shader.ts +22 -16
  107. package/src/adapter/resources/webgpu-texture.ts +54 -25
  108. package/src/adapter/resources/webgpu-vertex-array.ts +83 -0
  109. package/src/adapter/webgpu-canvas-context.ts +51 -26
  110. package/src/adapter/webgpu-device.ts +144 -48
  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,69 +1,68 @@
1
- import type {Binding, RenderPass, Shader} 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 {Binding, UniformValue, RenderPass, VertexArray} from '@luma.gl/core';
4
+ import {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';
6
- import {getVertexBufferLayout, getBufferSlots} from '../helpers/get-vertex-buffer-layout';
8
+ import {getVertexBufferLayout} from '../helpers/get-vertex-buffer-layout';
7
9
  // import {convertAttributesVertexBufferToLayout} from '../helpers/get-vertex-buffer-layout';
8
10
  // import {mapAccessorToWebGPUFormat} from './helpers/accessor-to-format';
9
11
  // import type {BufferAccessors} from './webgpu-pipeline';
10
12
 
11
- import type WebGPUDevice from '../webgpu-device';
12
- import type WebGPUBuffer from './webgpu-buffer';
13
- import type WebGPUShader from './webgpu-shader';
14
- import type WebGPURenderPass from './webgpu-render-pass';
13
+ import type {WebGPUDevice} from '../webgpu-device';
14
+ // import type {WebGPUBuffer} from './webgpu-buffer';
15
+ import type {WebGPUShader} from './webgpu-shader';
16
+ import type {WebGPURenderPass} from './webgpu-render-pass';
15
17
 
16
18
  // RENDER PIPELINE
17
19
 
18
20
  /** Creates a new render pipeline when parameters change */
19
- export default class WebGPURenderPipeline extends RenderPipeline {
21
+ export class WebGPURenderPipeline extends RenderPipeline {
20
22
  device: WebGPUDevice;
21
23
  handle: GPURenderPipeline;
22
24
 
23
25
  vs: WebGPUShader;
24
26
  fs: WebGPUShader | null = null;
25
27
 
26
- private _bufferSlots: Record<string, number>;
27
- private _buffers: Buffer[];
28
- private _indexBuffer: WebGPUBuffer | null = null;
28
+ // private _bufferSlots: Record<string, number>;
29
+ // private _buffers: Buffer[];
29
30
  // private _firstIndex: number;
30
31
  // private _lastIndex: number;
31
32
 
32
33
  /** For internal use to create BindGroups */
33
- private _bindGroupLayout: GPUBindGroupLayout;
34
+ private _bindGroupLayout: GPUBindGroupLayout | null = null;
34
35
  private _bindGroup: GPUBindGroup | null = null;
35
36
 
36
37
  constructor(device: WebGPUDevice, props: RenderPipelineProps) {
37
38
  super(device, props);
38
39
  this.device = device;
39
- this.handle = (this.props.handle as GPURenderPipeline) || this.createHandle();
40
+ this.handle = this.props.handle as GPURenderPipeline;
41
+ if (!this.handle) {
42
+ const descriptor = this._getRenderPipelineDescriptor();
43
+ log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
44
+ log.probe(1, JSON.stringify(descriptor, null, 2))();
45
+ log.groupEnd(1)();
46
+ this.handle = this.device.handle.createRenderPipeline(descriptor);
47
+ }
40
48
  this.handle.label = this.props.id;
41
49
 
42
50
  this.vs = cast<WebGPUShader>(props.vs);
43
51
  this.fs = cast<WebGPUShader>(props.fs);
44
52
 
45
- this._bufferSlots = getBufferSlots(this.props.layout, this.props.bufferMap);
46
- this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
47
- this._bindGroupLayout = this.handle.getBindGroupLayout(0);
48
- }
49
-
50
- protected createHandle(): GPURenderPipeline {
51
- const descriptor = this._getRenderPipelineDescriptor();
52
- const renderPipeline = this.device.handle.createRenderPipeline(descriptor);
53
- log.groupCollapsed(1, `new WebGPRenderPipeline(${this.id})`)();
54
- log.log(1, JSON.stringify(descriptor, null, 2))();
55
- log.groupEnd(1)();
56
- return renderPipeline;
53
+ // this._bufferSlots = getBufferSlots(this.props.shaderLayout, this.props.bufferLayout);
54
+ // this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
57
55
  }
58
56
 
59
- destroy() {
57
+ override destroy(): void {
60
58
  // WebGPURenderPipeline has no destroy method.
61
59
  }
62
60
 
63
- setIndexBuffer(indexBuffer: Buffer): void {
64
- this._indexBuffer = cast<WebGPUBuffer>(indexBuffer);
65
- }
61
+ // setIndexBuffer(indexBuffer: Buffer): void {
62
+ // this._indexBuffer = cast<WebGPUBuffer>(indexBuffer);
63
+ // }
66
64
 
65
+ /*
67
66
  setAttributes(attributes: Record<string, Buffer>): void {
68
67
  for (const [name, buffer] of Object.entries(attributes)) {
69
68
  const bufferIndex = this._bufferSlots[name];
@@ -82,44 +81,104 @@ export default class WebGPURenderPipeline extends RenderPipeline {
82
81
  // }
83
82
  // }
84
83
  }
84
+ */
85
+
86
+ // setConstantAttributes(attributes: Record<string, TypedArray>): void {
87
+ // throw new Error('not implemented');
88
+ // }
85
89
 
86
- /** Set the bindings */
87
90
  setBindings(bindings: Record<string, Binding>): void {
88
91
  if (!isObjectEmpty(this.props.bindings)) {
92
+ // Do we want to save things on CPU side?
89
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
+
90
98
  // Set up the bindings
91
99
  this._bindGroup = getBindGroup(
92
100
  this.device.handle,
93
101
  this._bindGroupLayout,
94
- this.props.layout,
102
+ this.props.shaderLayout,
95
103
  this.props.bindings
96
104
  );
97
105
  }
98
106
  }
99
107
 
100
- setUniforms(uniforms: Record<string, any>): void {
108
+ setUniforms(uniforms: Record<string, UniformValue>): void {
101
109
  if (!isObjectEmpty(uniforms)) {
102
110
  throw new Error('WebGPU does not support uniforms');
103
111
  }
104
112
  }
105
113
 
106
- _getBuffers() {
107
- return this._buffers;
114
+ draw(options: {
115
+ renderPass: RenderPass;
116
+ vertexArray: VertexArray;
117
+ vertexCount?: number;
118
+ indexCount?: number;
119
+ instanceCount?: number;
120
+ firstVertex?: number;
121
+ firstIndex?: number;
122
+ firstInstance?: number;
123
+ baseVertex?: number;
124
+ }): void {
125
+ const webgpuRenderPass: WebGPURenderPass =
126
+ cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
127
+
128
+ // Set pipeline
129
+ webgpuRenderPass.handle.setPipeline(this.handle);
130
+
131
+ // Set bindings (uniform buffers, textures etc)
132
+ const bindGroup = this._getBindGroup();
133
+ if (bindGroup) {
134
+ webgpuRenderPass.handle.setBindGroup(0, bindGroup);
135
+ }
136
+
137
+
138
+ // Set attributes
139
+ // Note: Rebinds constant attributes before each draw call
140
+ options.vertexArray.bindBeforeRender(options.renderPass);
141
+
142
+ // Draw
143
+ if (options.indexCount) {
144
+ webgpuRenderPass.handle.drawIndexed(
145
+ options.indexCount,
146
+ options.instanceCount,
147
+ options.firstIndex,
148
+ options.baseVertex,
149
+ options.firstInstance
150
+ );
151
+ } else {
152
+ webgpuRenderPass.handle.draw(
153
+ options.vertexCount || 0,
154
+ options.instanceCount || 1, // If 0, nothing will be drawn
155
+ options.firstInstance
156
+ );
157
+ }
158
+
159
+ // Note: Rebinds constant attributes before each draw call
160
+ options.vertexArray.unbindAfterRender(options.renderPass);
108
161
  }
109
162
 
163
+ // _getBuffers() {
164
+ // return this._buffers;
165
+ // }
166
+
110
167
  /** Return a bind group created by setBindings */
111
168
  _getBindGroup() {
112
169
  // assert(this._bindGroup);
113
170
  return this._bindGroup;
114
171
  }
115
172
 
116
- /** Populate the complex WebGPU GPURenderPipelineDescriptor */
173
+ /**
174
+ * Populate the complex WebGPU GPURenderPipelineDescriptor
175
+ */
117
176
  protected _getRenderPipelineDescriptor() {
118
177
  // Set up the vertex stage
119
178
  const vertex: GPUVertexState = {
120
179
  module: cast<WebGPUShader>(this.props.vs).handle,
121
180
  entryPoint: this.props.vsEntryPoint || 'main',
122
- buffers: getVertexBufferLayout(this.props.layout, this.props.bufferMap)
181
+ buffers: getVertexBufferLayout(this.props.shaderLayout, this.props.bufferLayout)
123
182
  };
124
183
 
125
184
  // Set up the fragment stage
@@ -131,7 +190,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
131
190
  targets: [
132
191
  {
133
192
  // TODO exclamation mark hack!
134
- format: getWebGPUTextureFormat(this.device?.canvasContext?.format!)
193
+ format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
135
194
  }
136
195
  ]
137
196
  };
@@ -139,19 +198,20 @@ export default class WebGPURenderPipeline extends RenderPipeline {
139
198
 
140
199
  // WebGPU has more restrictive topology support than WebGL
141
200
  switch (this.props.topology) {
142
- case 'triangle-fan':
143
- case 'line-loop':
201
+ case 'triangle-fan-webgl':
202
+ case 'line-loop-webgl':
144
203
  throw new Error(`WebGPU does not support primitive topology ${this.props.topology}`);
145
204
  default:
146
205
  }
147
206
 
148
207
  // Create a partially populated descriptor
149
- let descriptor: GPURenderPipelineDescriptor = {
208
+ const descriptor: GPURenderPipelineDescriptor = {
150
209
  vertex,
151
210
  fragment,
152
211
  primitive: {
153
212
  topology: this.props.topology
154
- }
213
+ },
214
+ layout: 'auto'
155
215
  };
156
216
 
157
217
  // Set parameters on the descriptor
@@ -160,49 +220,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
160
220
  return descriptor;
161
221
  }
162
222
 
163
- draw(options: {
164
- renderPass?: RenderPass;
165
- vertexCount?: number;
166
- indexCount?: number;
167
- instanceCount?: number;
168
- firstVertex?: number;
169
- firstIndex?: number;
170
- firstInstance?: number;
171
- baseVertex?: number;
172
- }): void {
173
- const webgpuRenderPass =
174
- cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
175
-
176
- // Set pipeline
177
- webgpuRenderPass.handle.setPipeline(this.handle);
178
-
179
- // Set bindings (uniform buffers, textures etc)
180
- if (this._getBindGroup()) {
181
- webgpuRenderPass.handle.setBindGroup(0, this._getBindGroup());
182
- }
183
-
184
- // Set attributes
185
- this._setAttributeBuffers(webgpuRenderPass);
186
-
187
- // Draw
188
- if (options.indexCount) {
189
- webgpuRenderPass.handle.drawIndexed(
190
- options.indexCount,
191
- options.instanceCount,
192
- options.firstIndex,
193
- options.baseVertex,
194
- options.firstInstance
195
- );
196
- } else {
197
- webgpuRenderPass.handle.draw(
198
- options.vertexCount || 0,
199
- options.instanceCount,
200
- options.firstIndex,
201
- options.firstInstance
202
- );
203
- }
204
- }
205
-
223
+ /**
206
224
  _setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
207
225
  if (this._indexBuffer) {
208
226
  webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
@@ -212,7 +230,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
212
230
  for (let i = 0; i < buffers.length; ++i) {
213
231
  const buffer = cast<WebGPUBuffer>(buffers[i]);
214
232
  if (!buffer) {
215
- const attribute = this.props.layout.attributes.find(
233
+ const attribute = this.props.shaderLayout.attributes.find(
216
234
  (attribute) => attribute.location === i
217
235
  );
218
236
  throw new Error(
@@ -224,7 +242,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
224
242
 
225
243
  // TODO - HANDLE buffer maps
226
244
  /*
227
- for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferMap)) {
245
+ for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
228
246
  const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
229
247
  if (!buffer) {
230
248
  log.warn(`Missing buffer for buffer map ${bufferName}`)();
@@ -241,6 +259,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
241
259
  }
242
260
  }
243
261
  }
244
- */
262
+ *
245
263
  }
264
+ */
246
265
  }
@@ -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,7 +8,7 @@ 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
 
@@ -17,16 +17,16 @@ export default class WebGPUSampler extends Sampler {
17
17
  this.device = device;
18
18
 
19
19
  // Prepare sampler props
20
- const samplerProps = this.props;
20
+ const samplerProps: Partial<WebGPUSamplerProps> = {...this.props};
21
21
  if (samplerProps.type !== 'comparison-sampler') {
22
22
  delete samplerProps.compare;
23
23
  }
24
24
 
25
- this.handle = this.handle || this.device.handle.createSampler(this.props);
25
+ this.handle = this.handle || this.device.handle.createSampler(samplerProps);
26
26
  this.handle.label = this.props.id;
27
27
  }
28
28
 
29
- destroy(): void {
29
+ override destroy(): void {
30
30
  // this.handle.destroy();
31
31
  }
32
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,10 +28,10 @@ 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
- const shaderLog = await this.compilationInfo();
34
+ const shaderLog = await this.getCompilationInfo();
32
35
  log.error(`Shader compilation error: ${error.message}`, shaderLog)();
33
36
  // Note: Even though this error is asynchronous and thrown after the constructor completes,
34
37
  // it will result in a useful stack trace leading back to the constructor
@@ -36,16 +39,25 @@ export default class WebGPUShader extends Shader {
36
39
  }
37
40
  }
38
41
 
39
- destroy() {
42
+ override destroy(): void {
43
+ // Note: WebGPU does not offer a method to destroy shaders
40
44
  // this.handle.destroy();
41
45
  }
42
46
 
47
+ /** Returns compilation info for this shader */
48
+ async getCompilationInfo(): Promise<readonly CompilerMessage[]> {
49
+ const compilationInfo = await this.handle.getCompilationInfo();
50
+ return compilationInfo.messages;
51
+ }
52
+
53
+ // PRIVATE METHODS
54
+
43
55
  protected createHandle(): GPUShaderModule {
44
- const {source} = this.props;
56
+ const {source, stage} = this.props;
45
57
 
46
58
  let language = this.props.language;
47
59
  // Compile from src
48
- if (!language) {
60
+ if (language === 'auto') {
49
61
  // wgsl uses C++ "auto" style arrow notation
50
62
  language = source.includes('->') ? 'wgsl' : 'glsl';
51
63
  }
@@ -57,16 +69,10 @@ export default class WebGPUShader extends Shader {
57
69
  return this.device.handle.createShaderModule({
58
70
  code: source,
59
71
  // @ts-expect-error
60
- transform: (glsl) => this.device.glslang.compileGLSL(glsl, type)
72
+ transform: (glsl) => this.device.glslang.compileGLSL(glsl, stage)
61
73
  });
62
74
  default:
63
75
  throw new Error(language);
64
76
  }
65
77
  }
66
-
67
- /** Returns compilation info for this shader */
68
- async compilationInfo(): Promise<readonly CompilerMessage[]> {
69
- const compilationInfo = await this.handle.compilationInfo();
70
- return compilationInfo.messages;
71
- }
72
78
  }
@@ -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,11 +13,14 @@ 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
- sampler: WebGPUSampler = null;
20
+ sampler: WebGPUSampler;
21
+
22
+ override height: number = 1;
23
+ override width: number = 1;
21
24
 
22
25
  // static async createFromImageURL(src, usage = 0) {
23
26
  // const img = document.createElement('img');
@@ -29,39 +32,57 @@ export default class WebGPUTexture extends Texture {
29
32
  constructor(device: WebGPUDevice, props: TextureProps) {
30
33
  super(device, props);
31
34
 
32
- if (typeof this.props.format === 'number') {
33
- throw new Error('number format');
35
+ this.device = device;
36
+
37
+ if (props.data instanceof Promise) {
38
+ props.data.then(resolvedImageData => {
39
+ // @ts-expect-error
40
+ this.props = {...props, data: resolvedImageData};
41
+ this.initialize(this.props);
42
+ });
43
+ return;
34
44
  }
35
45
 
36
- this.device = device;
46
+ this.initialize(props);
47
+ }
48
+
49
+ protected initialize(props: TextureProps): void {
50
+ // @ts-expect-error
37
51
  this.handle = this.props.handle || this.createHandle();
52
+ this.handle.label ||= this.id;
38
53
 
39
54
  if (this.props.data) {
40
- this.setData({data: this.props.data} );
55
+ this.setData({data: this.props.data});
41
56
  }
42
57
 
58
+ this.width = this.handle.width;
59
+ this.height = this.handle.height;
60
+ // Why not just read all properties directly from the texture
61
+ // this.depthOrArrayLayers = this.handle.depthOrArrayLayers;
62
+ // this.mipLevelCount = this.handle.mipLevelCount;
63
+ // this.sampleCount = this.handle.sampleCount;
64
+ // this.dimension = this.handle.dimension;
65
+ // this.format = this.handle.format;
66
+ // this.usage = this.handle.usage;
67
+
43
68
  // Create a default sampler. This mimics the WebGL1 API where sampler props are stored on the texture
44
69
  // this.setSampler(props.sampler);
45
70
  this.sampler = props.sampler instanceof WebGPUSampler ? props.sampler : new WebGPUSampler(this.device, props.sampler);
46
71
 
47
72
  // TODO - To support texture arrays we need to create custom views...
48
73
  // But we are not ready to expose TextureViews to the public API.
49
- this.view = this.handle.createView({
50
- // format: this.props.format,
51
- // dimension: this.props.dimension,
52
- // aspect = "all";
53
- // baseMipLevel: 0;
54
- // mipLevelCount;
55
- // baseArrayLayer = 0;
56
- // arrayLayerCount;
57
- });
74
+ // @ts-expect-error
75
+ this.view = this.createView();
76
+ // format: this.props.format,
77
+ // dimension: this.props.dimension,
78
+ // aspect = "all";
79
+ // baseMipLevel: 0;
80
+ // mipLevelCount;
81
+ // baseArrayLayer = 0;
82
+ // arrayLayerCount;
58
83
  }
59
84
 
60
85
  protected createHandle(): GPUTexture {
61
- if (typeof this.props.format === 'number') {
62
- throw new Error('number format');
63
- }
64
-
65
86
  // Deduce size from data - TODO this is a hack
66
87
  // @ts-expect-error
67
88
  const width = this.props.width || this.props.data?.width || 1;
@@ -69,6 +90,7 @@ export default class WebGPUTexture extends Texture {
69
90
  const height = this.props.height || this.props.data?.height || 1;
70
91
 
71
92
  return this.device.handle.createTexture({
93
+ label: this.id,
72
94
  size: {
73
95
  width,
74
96
  height,
@@ -82,7 +104,7 @@ export default class WebGPUTexture extends Texture {
82
104
  });
83
105
  }
84
106
 
85
- destroy(): void {
107
+ override destroy(): void {
86
108
  this.handle.destroy();
87
109
  }
88
110
 
@@ -116,7 +138,7 @@ export default class WebGPUTexture extends Texture {
116
138
  aspect?: 'all' | 'stencil-only' | 'depth-only';
117
139
  colorSpace?: 'srgb';
118
140
  premultipliedAlpha?: boolean;
119
- }): this {
141
+ }): {width: number, height: number} {
120
142
  const {
121
143
  source,
122
144
  width = options.source.width,
@@ -157,9 +179,16 @@ export default class WebGPUTexture extends Texture {
157
179
  depth
158
180
  ]
159
181
  );
160
- return this;
182
+ return {width, height};
161
183
  }
162
184
 
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
+
163
192
  /*
164
193
  async readPixels() {
165
194
  const readbackBuffer = device.createBuffer({
@@ -0,0 +1,83 @@
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
+ if (webgpuIndexBuffer?.handle) {
64
+ // Note we can't unset an index buffer
65
+ log.warn('setting index buffer', webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType)();
66
+ webgpuRenderPass.handle.setIndexBuffer(webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType);
67
+ }
68
+ for (let location = 0; location < this.maxVertexAttributes; location++) {
69
+ const webgpuBuffer = this.attributes[location] as WebGPUBuffer;
70
+ if (webgpuBuffer?.handle) {
71
+ log.warn('setting vertex buffer', location, webgpuBuffer?.handle)();
72
+ webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer?.handle);
73
+ }
74
+ }
75
+ // TODO - emit warnings/errors/throw if constants have been set on this vertex array
76
+ }
77
+
78
+ override unbindAfterRender(renderPass: RenderPass): void {
79
+ // On WebGPU we don't need to unbind.
80
+ // In fact we can't easily do it. setIndexBuffer/setVertexBuffer don't accept null.
81
+ // Unbinding presumably happens automatically when the render pass is ended.
82
+ }
83
+ }