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

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 +39 -43
  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 +46 -118
  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 +16 -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 +3142 -0
  81. package/dist/glsl/glsllang.js +0 -1
  82. package/dist/glsl/glsllang.js.map +1 -1
  83. package/dist/index.cjs +1550 -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 +65 -39
  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 +117 -97
  105. package/src/adapter/resources/webgpu-sampler.ts +6 -6
  106. package/src/adapter/resources/webgpu-shader.ts +25 -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,105 @@ 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
- if (!isObjectEmpty(this.props.bindings)) {
89
- Object.assign(this.props.bindings, bindings);
90
- // Set up the bindings
91
- this._bindGroup = getBindGroup(
92
- this.device.handle,
93
- this._bindGroupLayout,
94
- this.props.layout,
95
- this.props.bindings
96
- );
97
- }
91
+ // if (isObjectEmpty(bindings)) {
92
+ // return;
93
+ // }
94
+
95
+ // Do we want to save things on CPU side?
96
+ Object.assign(this.props.bindings, bindings);
98
97
  }
99
98
 
100
- setUniforms(uniforms: Record<string, any>): void {
99
+ setUniforms(uniforms: Record<string, UniformValue>): void {
101
100
  if (!isObjectEmpty(uniforms)) {
102
101
  throw new Error('WebGPU does not support uniforms');
103
102
  }
104
103
  }
105
104
 
106
- _getBuffers() {
107
- return this._buffers;
105
+ draw(options: {
106
+ renderPass: RenderPass;
107
+ vertexArray: VertexArray;
108
+ vertexCount?: number;
109
+ indexCount?: number;
110
+ instanceCount?: number;
111
+ firstVertex?: number;
112
+ firstIndex?: number;
113
+ firstInstance?: number;
114
+ baseVertex?: number;
115
+ }): void {
116
+ const webgpuRenderPass: WebGPURenderPass =
117
+ cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
118
+
119
+ // Set pipeline
120
+ webgpuRenderPass.handle.setPipeline(this.handle);
121
+
122
+ // Set bindings (uniform buffers, textures etc)
123
+ const bindGroup = this._getBindGroup();
124
+ if (bindGroup) {
125
+ webgpuRenderPass.handle.setBindGroup(0, bindGroup);
126
+ }
127
+
128
+
129
+ // Set attributes
130
+ // Note: Rebinds constant attributes before each draw call
131
+ options.vertexArray.bindBeforeRender(options.renderPass);
132
+
133
+ // Draw
134
+ if (options.indexCount) {
135
+ webgpuRenderPass.handle.drawIndexed(
136
+ options.indexCount,
137
+ options.instanceCount,
138
+ options.firstIndex,
139
+ options.baseVertex,
140
+ options.firstInstance
141
+ );
142
+ } else {
143
+ webgpuRenderPass.handle.draw(
144
+ options.vertexCount || 0,
145
+ options.instanceCount || 1, // If 0, nothing will be drawn
146
+ options.firstInstance
147
+ );
148
+ }
149
+
150
+ // Note: Rebinds constant attributes before each draw call
151
+ options.vertexArray.unbindAfterRender(options.renderPass);
108
152
  }
109
153
 
154
+ // _getBuffers() {
155
+ // return this._buffers;
156
+ // }
157
+
110
158
  /** Return a bind group created by setBindings */
111
159
  _getBindGroup() {
112
- // assert(this._bindGroup);
160
+ // Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
161
+ this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
162
+
163
+ // Set up the bindings
164
+ this._bindGroup = this._bindGroup || getBindGroup(
165
+ this.device.handle,
166
+ this._bindGroupLayout,
167
+ this.props.shaderLayout,
168
+ this.props.bindings
169
+ );
170
+
113
171
  return this._bindGroup;
114
172
  }
115
173
 
116
- /** Populate the complex WebGPU GPURenderPipelineDescriptor */
174
+ /**
175
+ * Populate the complex WebGPU GPURenderPipelineDescriptor
176
+ */
117
177
  protected _getRenderPipelineDescriptor() {
118
178
  // Set up the vertex stage
119
179
  const vertex: GPUVertexState = {
120
180
  module: cast<WebGPUShader>(this.props.vs).handle,
121
181
  entryPoint: this.props.vsEntryPoint || 'main',
122
- buffers: getVertexBufferLayout(this.props.layout, this.props.bufferMap)
182
+ buffers: getVertexBufferLayout(this.props.shaderLayout, this.props.bufferLayout)
123
183
  };
124
184
 
125
185
  // Set up the fragment stage
@@ -131,7 +191,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
131
191
  targets: [
132
192
  {
133
193
  // TODO exclamation mark hack!
134
- format: getWebGPUTextureFormat(this.device?.canvasContext?.format!)
194
+ format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
135
195
  }
136
196
  ]
137
197
  };
@@ -139,19 +199,20 @@ export default class WebGPURenderPipeline extends RenderPipeline {
139
199
 
140
200
  // WebGPU has more restrictive topology support than WebGL
141
201
  switch (this.props.topology) {
142
- case 'triangle-fan':
143
- case 'line-loop':
202
+ case 'triangle-fan-webgl':
203
+ case 'line-loop-webgl':
144
204
  throw new Error(`WebGPU does not support primitive topology ${this.props.topology}`);
145
205
  default:
146
206
  }
147
207
 
148
208
  // Create a partially populated descriptor
149
- let descriptor: GPURenderPipelineDescriptor = {
209
+ const descriptor: GPURenderPipelineDescriptor = {
150
210
  vertex,
151
211
  fragment,
152
212
  primitive: {
153
213
  topology: this.props.topology
154
- }
214
+ },
215
+ layout: 'auto'
155
216
  };
156
217
 
157
218
  // Set parameters on the descriptor
@@ -160,49 +221,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
160
221
  return descriptor;
161
222
  }
162
223
 
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
-
224
+ /**
206
225
  _setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
207
226
  if (this._indexBuffer) {
208
227
  webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
@@ -212,7 +231,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
212
231
  for (let i = 0; i < buffers.length; ++i) {
213
232
  const buffer = cast<WebGPUBuffer>(buffers[i]);
214
233
  if (!buffer) {
215
- const attribute = this.props.layout.attributes.find(
234
+ const attribute = this.props.shaderLayout.attributes.find(
216
235
  (attribute) => attribute.location === i
217
236
  );
218
237
  throw new Error(
@@ -224,7 +243,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
224
243
 
225
244
  // TODO - HANDLE buffer maps
226
245
  /*
227
- for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferMap)) {
246
+ for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
228
247
  const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
229
248
  if (!buffer) {
230
249
  log.warn(`Missing buffer for buffer map ${bufferName}`)();
@@ -241,6 +260,7 @@ export default class WebGPURenderPipeline extends RenderPipeline {
241
260
  }
242
261
  }
243
262
  }
244
- */
263
+ *
245
264
  }
265
+ */
246
266
  }
@@ -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,13 @@ 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
+ // The `Shader` base class will determine if debug window should be opened based on props
35
+ this.debugShader();
36
+
37
+ const shaderLog = await this.getCompilationInfo();
32
38
  log.error(`Shader compilation error: ${error.message}`, shaderLog)();
33
39
  // Note: Even though this error is asynchronous and thrown after the constructor completes,
34
40
  // it will result in a useful stack trace leading back to the constructor
@@ -36,16 +42,25 @@ export default class WebGPUShader extends Shader {
36
42
  }
37
43
  }
38
44
 
39
- destroy() {
45
+ override destroy(): void {
46
+ // Note: WebGPU does not offer a method to destroy shaders
40
47
  // this.handle.destroy();
41
48
  }
42
49
 
50
+ /** Returns compilation info for this shader */
51
+ async getCompilationInfo(): Promise<readonly CompilerMessage[]> {
52
+ const compilationInfo = await this.handle.getCompilationInfo();
53
+ return compilationInfo.messages;
54
+ }
55
+
56
+ // PRIVATE METHODS
57
+
43
58
  protected createHandle(): GPUShaderModule {
44
- const {source} = this.props;
59
+ const {source, stage} = this.props;
45
60
 
46
61
  let language = this.props.language;
47
62
  // Compile from src
48
- if (!language) {
63
+ if (language === 'auto') {
49
64
  // wgsl uses C++ "auto" style arrow notation
50
65
  language = source.includes('->') ? 'wgsl' : 'glsl';
51
66
  }
@@ -57,16 +72,10 @@ export default class WebGPUShader extends Shader {
57
72
  return this.device.handle.createShaderModule({
58
73
  code: source,
59
74
  // @ts-expect-error
60
- transform: (glsl) => this.device.glslang.compileGLSL(glsl, type)
75
+ transform: (glsl) => this.device.glslang.compileGLSL(glsl, stage)
61
76
  });
62
77
  default:
63
78
  throw new Error(language);
64
79
  }
65
80
  }
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
81
  }
@@ -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 bufferSlot in vertex attributes array to a buffer, enables the bufferSlot, sets divisor */
46
+ setBuffer(bufferSlot: 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[bufferSlot] = 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
+ }