@luma.gl/webgpu 9.2.0-alpha.1 → 9.2.0-alpha.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 (86) hide show
  1. package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
  2. package/dist/adapter/helpers/get-bind-group.js +3 -2
  3. package/dist/adapter/helpers/get-bind-group.js.map +1 -1
  4. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
  5. package/dist/adapter/helpers/get-vertex-buffer-layout.js +17 -6
  6. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -1
  7. package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -1
  8. package/dist/adapter/helpers/webgpu-parameters.js +27 -7
  9. package/dist/adapter/helpers/webgpu-parameters.js.map +1 -1
  10. package/dist/adapter/resources/webgpu-buffer.d.ts +13 -16
  11. package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
  12. package/dist/adapter/resources/webgpu-buffer.js +130 -103
  13. package/dist/adapter/resources/webgpu-buffer.js.map +1 -1
  14. package/dist/adapter/resources/webgpu-command-buffer.d.ts +2 -2
  15. package/dist/adapter/resources/webgpu-command-buffer.d.ts.map +1 -1
  16. package/dist/adapter/resources/webgpu-command-buffer.js.map +1 -1
  17. package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
  18. package/dist/adapter/resources/webgpu-command-encoder.js +8 -1
  19. package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -1
  20. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +2 -2
  21. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
  22. package/dist/adapter/resources/webgpu-compute-pipeline.js.map +1 -1
  23. package/dist/adapter/resources/webgpu-external-texture.d.ts +2 -2
  24. package/dist/adapter/resources/webgpu-external-texture.d.ts.map +1 -1
  25. package/dist/adapter/resources/webgpu-external-texture.js.map +1 -1
  26. package/dist/adapter/resources/webgpu-framebuffer.d.ts +3 -2
  27. package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -1
  28. package/dist/adapter/resources/webgpu-framebuffer.js +1 -0
  29. package/dist/adapter/resources/webgpu-framebuffer.js.map +1 -1
  30. package/dist/adapter/resources/webgpu-pipeline-layout.d.ts +10 -0
  31. package/dist/adapter/resources/webgpu-pipeline-layout.d.ts.map +1 -0
  32. package/dist/adapter/resources/webgpu-pipeline-layout.js +104 -0
  33. package/dist/adapter/resources/webgpu-pipeline-layout.js.map +1 -0
  34. package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
  35. package/dist/adapter/resources/webgpu-render-pass.js +14 -7
  36. package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
  37. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +4 -4
  38. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  39. package/dist/adapter/resources/webgpu-render-pipeline.js +12 -11
  40. package/dist/adapter/resources/webgpu-render-pipeline.js.map +1 -1
  41. package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
  42. package/dist/adapter/resources/webgpu-shader.js +7 -8
  43. package/dist/adapter/resources/webgpu-shader.js.map +1 -1
  44. package/dist/adapter/resources/webgpu-texture-view.d.ts.map +1 -1
  45. package/dist/adapter/resources/webgpu-texture-view.js +3 -4
  46. package/dist/adapter/resources/webgpu-texture-view.js.map +1 -1
  47. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  48. package/dist/adapter/resources/webgpu-texture.js +19 -22
  49. package/dist/adapter/resources/webgpu-texture.js.map +1 -1
  50. package/dist/adapter/resources/webgpu-vertex-array.d.ts.map +1 -1
  51. package/dist/adapter/resources/webgpu-vertex-array.js.map +1 -1
  52. package/dist/adapter/webgpu-adapter.d.ts.map +1 -1
  53. package/dist/adapter/webgpu-adapter.js +40 -36
  54. package/dist/adapter/webgpu-adapter.js.map +1 -1
  55. package/dist/adapter/webgpu-canvas-context.d.ts +3 -3
  56. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
  57. package/dist/adapter/webgpu-canvas-context.js +1 -0
  58. package/dist/adapter/webgpu-canvas-context.js.map +1 -1
  59. package/dist/adapter/webgpu-device.d.ts +10 -4
  60. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  61. package/dist/adapter/webgpu-device.js +30 -17
  62. package/dist/adapter/webgpu-device.js.map +1 -1
  63. package/dist/dist.dev.js +470 -232
  64. package/dist/dist.min.js +6 -5
  65. package/dist/index.cjs +449 -228
  66. package/dist/index.cjs.map +4 -4
  67. package/package.json +3 -3
  68. package/src/adapter/helpers/get-bind-group.ts +3 -2
  69. package/src/adapter/helpers/get-vertex-buffer-layout.ts +20 -7
  70. package/src/adapter/helpers/webgpu-parameters.ts +32 -8
  71. package/src/adapter/resources/webgpu-buffer.ts +161 -112
  72. package/src/adapter/resources/webgpu-command-buffer.ts +2 -2
  73. package/src/adapter/resources/webgpu-command-encoder.ts +8 -1
  74. package/src/adapter/resources/webgpu-compute-pipeline.ts +2 -2
  75. package/src/adapter/resources/webgpu-external-texture.ts +2 -2
  76. package/src/adapter/resources/webgpu-framebuffer.ts +3 -2
  77. package/src/adapter/resources/webgpu-pipeline-layout.ts +131 -0
  78. package/src/adapter/resources/webgpu-render-pass.ts +19 -9
  79. package/src/adapter/resources/webgpu-render-pipeline.ts +17 -15
  80. package/src/adapter/resources/webgpu-shader.ts +11 -8
  81. package/src/adapter/resources/webgpu-texture-view.ts +3 -4
  82. package/src/adapter/resources/webgpu-texture.ts +23 -25
  83. package/src/adapter/resources/webgpu-vertex-array.ts +1 -1
  84. package/src/adapter/webgpu-adapter.ts +51 -47
  85. package/src/adapter/webgpu-canvas-context.ts +5 -4
  86. package/src/adapter/webgpu-device.ts +39 -19
package/dist/dist.dev.js CHANGED
@@ -49,9 +49,6 @@ var __exports__ = (() => {
49
49
  });
50
50
 
51
51
  // src/adapter/resources/webgpu-buffer.ts
52
- function getByteLength(props) {
53
- return props.byteLength || props.data?.byteLength || 0;
54
- }
55
52
  var import_core, WebGPUBuffer;
56
53
  var init_webgpu_buffer = __esm({
57
54
  "src/adapter/resources/webgpu-buffer.ts"() {
@@ -64,76 +61,151 @@ var __exports__ = (() => {
64
61
  constructor(device, props) {
65
62
  super(device, props);
66
63
  this.device = device;
67
- this.byteLength = getByteLength(props);
68
- const mapBuffer = Boolean(props.data);
64
+ this.byteLength = props.byteLength || props.data?.byteLength || 0;
65
+ const mappedAtCreation = Boolean(this.props.onMapped || props.data);
69
66
  const size = Math.ceil(this.byteLength / 4) * 4;
70
- this.device.handle.pushErrorScope("out-of-memory");
71
- this.device.handle.pushErrorScope("validation");
67
+ this.device.pushErrorScope("out-of-memory");
68
+ this.device.pushErrorScope("validation");
72
69
  this.handle = this.props.handle || this.device.handle.createBuffer({
73
- size,
70
+ label: this.props.id,
74
71
  // usage defaults to vertex
75
72
  usage: this.props.usage || GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
76
- mappedAtCreation: this.props.mappedAtCreation || mapBuffer,
77
- label: this.props.id
73
+ mappedAtCreation,
74
+ size
78
75
  });
79
- this.device.handle.popErrorScope().then((error) => {
80
- if (error) {
81
- this.device.reportError(new Error(`Buffer validation failed: ${error.message}`), this);
82
- }
76
+ this.device.popErrorScope((error) => {
77
+ this.device.reportError(new Error(`${this} creation failed ${error.message}`), this)();
78
+ this.device.debug();
83
79
  });
84
- this.device.handle.popErrorScope().then((error) => {
85
- if (error) {
86
- this.device.reportError(new Error(`Buffer out of memory: ${error.message}`), this);
87
- }
80
+ this.device.popErrorScope((error) => {
81
+ this.device.reportError(new Error(`${this} out of memory: ${error.message}`), this)();
82
+ this.device.debug();
88
83
  });
89
- if (props.data) {
90
- this._writeMapped(props.data);
91
- }
92
- if (mapBuffer && !props.mappedAtCreation) {
93
- this.handle.unmap();
84
+ this.device.pushErrorScope("validation");
85
+ if (props.data || props.onMapped) {
86
+ try {
87
+ const arrayBuffer = this.handle.getMappedRange();
88
+ if (props.data) {
89
+ const typedArray = props.data;
90
+ new typedArray.constructor(arrayBuffer).set(typedArray);
91
+ } else {
92
+ props.onMapped?.(arrayBuffer, "mapped");
93
+ }
94
+ } finally {
95
+ this.handle.unmap();
96
+ }
94
97
  }
98
+ this.device.popErrorScope((error) => {
99
+ this.device.reportError(new Error(`${this} creation failed ${error.message}`), this)();
100
+ this.device.debug();
101
+ });
95
102
  }
96
103
  destroy() {
97
104
  this.handle?.destroy();
98
105
  this.handle = null;
99
106
  }
100
- // WebGPU provides multiple ways to write a buffer...
101
107
  write(data, byteOffset = 0) {
108
+ const arrayBuffer = ArrayBuffer.isView(data) ? data.buffer : data;
109
+ const dataByteOffset = ArrayBuffer.isView(data) ? data.byteOffset : 0;
110
+ this.device.pushErrorScope("validation");
102
111
  this.device.handle.queue.writeBuffer(
103
112
  this.handle,
104
113
  byteOffset,
105
- data.buffer,
106
- data.byteOffset,
114
+ arrayBuffer,
115
+ dataByteOffset,
107
116
  data.byteLength
108
117
  );
118
+ this.device.popErrorScope((error) => {
119
+ this.device.reportError(new Error(`${this}.write() ${error.message}`), this)();
120
+ this.device.debug();
121
+ });
122
+ }
123
+ async mapAndWriteAsync(callback, byteOffset = 0, byteLength = this.byteLength - byteOffset) {
124
+ const isMappable = (this.usage & import_core.Buffer.MAP_WRITE) !== 0;
125
+ const mappableBuffer = !isMappable ? this._getMappableBuffer(import_core.Buffer.MAP_WRITE | import_core.Buffer.COPY_SRC, 0, this.byteLength) : null;
126
+ const writeBuffer = mappableBuffer || this;
127
+ this.device.pushErrorScope("validation");
128
+ try {
129
+ await this.device.handle.queue.onSubmittedWorkDone();
130
+ await writeBuffer.handle.mapAsync(GPUMapMode.WRITE, byteOffset, byteLength);
131
+ const arrayBuffer = writeBuffer.handle.getMappedRange(byteOffset, byteLength);
132
+ await callback(arrayBuffer, "mapped");
133
+ writeBuffer.handle.unmap();
134
+ if (mappableBuffer) {
135
+ this._copyBuffer(mappableBuffer, byteOffset, byteLength);
136
+ }
137
+ } finally {
138
+ this.device.popErrorScope((error) => {
139
+ this.device.reportError(new Error(`${this}.mapAndWriteAsync() ${error.message}`), this)();
140
+ this.device.debug();
141
+ });
142
+ mappableBuffer?.destroy();
143
+ }
109
144
  }
110
- async readAsync(byteOffset = 0, byteLength = this.byteLength) {
111
- const tempBuffer = new WebGPUBuffer(this.device, {
112
- usage: import_core.Buffer.MAP_READ | import_core.Buffer.COPY_DST,
145
+ async readAsync(byteOffset = 0, byteLength = this.byteLength - byteOffset) {
146
+ return this.mapAndReadAsync(
147
+ (arrayBuffer) => new Uint8Array(arrayBuffer.slice(0)),
148
+ byteOffset,
113
149
  byteLength
114
- });
115
- const commandEncoder = this.device.handle.createCommandEncoder();
116
- commandEncoder.copyBufferToBuffer(this.handle, byteOffset, tempBuffer.handle, 0, byteLength);
117
- this.device.handle.queue.submit([commandEncoder.finish()]);
118
- await tempBuffer.handle.mapAsync(GPUMapMode.READ, byteOffset, byteLength);
119
- const arrayBuffer = tempBuffer.handle.getMappedRange().slice(0);
120
- tempBuffer.handle.unmap();
121
- tempBuffer.destroy();
122
- return new Uint8Array(arrayBuffer);
150
+ );
123
151
  }
124
- _writeMapped(typedArray) {
125
- const arrayBuffer = this.handle.getMappedRange();
126
- new typedArray.constructor(arrayBuffer).set(typedArray);
152
+ async mapAndReadAsync(callback, byteOffset = 0, byteLength = this.byteLength - byteOffset) {
153
+ if (byteOffset % 8 !== 0 || byteLength % 4 !== 0) {
154
+ throw new Error("byteOffset must be multiple of 8 and byteLength multiple of 4");
155
+ }
156
+ if (byteOffset + byteLength > this.handle.size) {
157
+ throw new Error("Mapping range exceeds buffer size");
158
+ }
159
+ const isMappable = (this.usage & import_core.Buffer.MAP_READ) !== 0;
160
+ const mappableBuffer = !isMappable ? this._getMappableBuffer(import_core.Buffer.MAP_READ | import_core.Buffer.COPY_DST, 0, this.byteLength) : null;
161
+ const readBuffer = mappableBuffer || this;
162
+ this.device.pushErrorScope("validation");
163
+ try {
164
+ await this.device.handle.queue.onSubmittedWorkDone();
165
+ if (mappableBuffer) {
166
+ mappableBuffer._copyBuffer(this);
167
+ }
168
+ await readBuffer.handle.mapAsync(GPUMapMode.READ, byteOffset, byteLength);
169
+ const arrayBuffer = readBuffer.handle.getMappedRange(byteOffset, byteLength);
170
+ const result = await callback(arrayBuffer, "mapped");
171
+ readBuffer.handle.unmap();
172
+ return result;
173
+ } finally {
174
+ this.device.popErrorScope((error) => {
175
+ this.device.reportError(new Error(`${this}.mapAndReadAsync() ${error.message}`), this)();
176
+ this.device.debug();
177
+ });
178
+ mappableBuffer?.destroy();
179
+ }
127
180
  }
128
- // WEBGPU API
129
- mapAsync(mode, offset = 0, size) {
130
- return this.handle.mapAsync(mode, offset, size);
181
+ readSyncWebGL(byteOffset, byteLength) {
182
+ throw new Error("Not implemented");
131
183
  }
132
- getMappedRange(offset = 0, size) {
133
- return this.handle.getMappedRange(offset, size);
184
+ // INTERNAL METHODS
185
+ /**
186
+ * @todo - A small set of mappable buffers could be cached on the device,
187
+ * however this goes against the goal of keeping core as a thin GPU API layer.
188
+ */
189
+ _getMappableBuffer(usage, byteOffset, byteLength) {
190
+ import_core.log.warn(`${this} is not readable, creating a temporary Buffer`);
191
+ const readableBuffer = new WebGPUBuffer(this.device, { usage, byteLength });
192
+ return readableBuffer;
134
193
  }
135
- unmap() {
136
- this.handle.unmap();
194
+ _copyBuffer(sourceBuffer, byteOffset = 0, byteLength = this.byteLength) {
195
+ this.device.pushErrorScope("validation");
196
+ const commandEncoder = this.device.handle.createCommandEncoder();
197
+ commandEncoder.copyBufferToBuffer(
198
+ sourceBuffer.handle,
199
+ byteOffset,
200
+ this.handle,
201
+ byteOffset,
202
+ byteLength
203
+ );
204
+ this.device.handle.queue.submit([commandEncoder.finish()]);
205
+ this.device.popErrorScope((error) => {
206
+ this.device.reportError(new Error(`${this}._getReadableBuffer() ${error.message}`), this)();
207
+ this.device.debug();
208
+ });
137
209
  }
138
210
  };
139
211
  }
@@ -209,10 +281,9 @@ var __exports__ = (() => {
209
281
  baseArrayLayer: this.props.baseArrayLayer,
210
282
  arrayLayerCount: this.props.arrayLayerCount
211
283
  });
212
- this.device.handle.popErrorScope().then((error) => {
213
- if (error) {
214
- this.device.reportError(new Error(`TextureView validation failed: ${error.message}`), this);
215
- }
284
+ this.device.popErrorScope((error) => {
285
+ this.device.reportError(new Error(`TextureView constructor: ${error.message}`), this)();
286
+ this.device.debug();
216
287
  });
217
288
  this.handle.label = this.props.id;
218
289
  }
@@ -243,8 +314,8 @@ var __exports__ = (() => {
243
314
  if (this.dimension === "cube") {
244
315
  this.depth = 6;
245
316
  }
246
- this.device.handle.pushErrorScope("out-of-memory");
247
- this.device.handle.pushErrorScope("validation");
317
+ this.device.pushErrorScope("out-of-memory");
318
+ this.device.pushErrorScope("validation");
248
319
  this.handle = this.props.handle || this.device.handle.createTexture({
249
320
  label: this.id,
250
321
  size: {
@@ -258,15 +329,13 @@ var __exports__ = (() => {
258
329
  mipLevelCount: this.mipLevels,
259
330
  sampleCount: this.props.samples
260
331
  });
261
- this.device.handle.popErrorScope().then((error) => {
262
- if (error) {
263
- this.device.reportError(new Error(`Texture validation failed: ${error.message}`), this);
264
- }
332
+ this.device.popErrorScope((error) => {
333
+ this.device.reportError(new Error(`${this} constructor: ${error.message}`), this)();
334
+ this.device.debug();
265
335
  });
266
- this.device.handle.popErrorScope().then((error) => {
267
- if (error) {
268
- this.device.reportError(new Error(`Texture out of memory: ${error.message}`), this);
269
- }
336
+ this.device.popErrorScope((error) => {
337
+ this.device.reportError(new Error(`${this} out of memory: ${error.message}`), this)();
338
+ this.device.debug();
270
339
  });
271
340
  if (this.props.handle) {
272
341
  this.handle.label ||= this.id;
@@ -278,7 +347,8 @@ var __exports__ = (() => {
278
347
  ...this.props,
279
348
  texture: this,
280
349
  mipLevelCount: this.mipLevels,
281
- arrayLayerCount: this.depth
350
+ // Note: arrayLayerCount controls the view of array textures, but does not apply to 3d texture depths
351
+ arrayLayerCount: this.dimension !== "3d" ? this.depth : 1
282
352
  });
283
353
  this._initializeData(props.data);
284
354
  }
@@ -292,7 +362,7 @@ var __exports__ = (() => {
292
362
  copyImageData(options_) {
293
363
  const { width, height, depth } = this;
294
364
  const options = this._normalizeCopyImageDataOptions(options_);
295
- this.device.handle.pushErrorScope("validation");
365
+ this.device.pushErrorScope("validation");
296
366
  this.device.handle.queue.writeTexture(
297
367
  // destination: GPUImageCopyTexture
298
368
  {
@@ -314,15 +384,14 @@ var __exports__ = (() => {
314
384
  // size: GPUExtent3D - extents of the content to write
315
385
  [width, height, depth]
316
386
  );
317
- this.device.handle.popErrorScope().then((error) => {
318
- if (error) {
319
- this.device.reportError(new Error(`copyImageData validation failed: ${error.message}`));
320
- }
387
+ this.device.popErrorScope((error) => {
388
+ this.device.reportError(new Error(`copyImageData: ${error.message}`), this)();
389
+ this.device.debug();
321
390
  });
322
391
  }
323
392
  copyExternalImage(options_) {
324
393
  const options = this._normalizeCopyExternalImageOptions(options_);
325
- this.device.handle.pushErrorScope("validation");
394
+ this.device.pushErrorScope("validation");
326
395
  this.device.handle.queue.copyExternalImageToTexture(
327
396
  // source: GPUImageCopyExternalImage
328
397
  {
@@ -333,7 +402,8 @@ var __exports__ = (() => {
333
402
  // destination: GPUImageCopyTextureTagged
334
403
  {
335
404
  texture: this.handle,
336
- origin: [options.x, options.y, options.depth],
405
+ origin: [options.x, options.y, 0],
406
+ // options.depth],
337
407
  mipLevel: options.mipLevel,
338
408
  aspect: options.aspect,
339
409
  colorSpace: options.colorSpace,
@@ -342,10 +412,9 @@ var __exports__ = (() => {
342
412
  // copySize: GPUExtent3D
343
413
  [options.width, options.height, 1]
344
414
  );
345
- this.device.handle.popErrorScope().then((error) => {
346
- if (error) {
347
- this.device.reportError(new Error(`copyExternalImage validation failed: ${error.message}`));
348
- }
415
+ this.device.popErrorScope((error) => {
416
+ this.device.reportError(new Error(`copyExternalImage: ${error.message}`), this)();
417
+ this.device.debug();
349
418
  });
350
419
  return { width: options.width, height: options.height };
351
420
  }
@@ -370,7 +439,7 @@ var __exports__ = (() => {
370
439
  device.submit([encoder.finish()]);
371
440
 
372
441
  // Get the data on the CPU.
373
- await buffer.mapAsync(GPUMapMode.READ);
442
+ await buffer.mapAndReadAsync(GPUMapMode.READ);
374
443
  saveScreenshot(buffer.getMappedRange());
375
444
  buffer.unmap();
376
445
  }
@@ -471,13 +540,16 @@ var __exports__ = (() => {
471
540
  if (this.props.language === "glsl" || isGLSL) {
472
541
  throw new Error("GLSL shaders are not supported in WebGPU");
473
542
  }
474
- this.device.handle.pushErrorScope("validation");
543
+ this.device.pushErrorScope("validation");
475
544
  this.handle = this.props.handle || this.device.handle.createShaderModule({ code: props.source });
476
- this.device.handle.popErrorScope().then((error) => {
477
- if (error) {
478
- import_core6.log.error(`${this} creation failed:
479
- "${error.message}"`, this, this.props.source)();
480
- }
545
+ this.device.popErrorScope((error) => {
546
+ this.device.reportError(
547
+ new Error(`${this} creation failed:
548
+ "${error.message}"`),
549
+ this,
550
+ this.props.source
551
+ )();
552
+ this.device.debug();
481
553
  });
482
554
  this.handle.label = this.props.id;
483
555
  this._checkCompilationError();
@@ -491,7 +563,8 @@ var __exports__ = (() => {
491
563
  this.compilationStatus = hasErrors ? "error" : "success";
492
564
  this.debugShader();
493
565
  if (this.compilationStatus === "error") {
494
- import_core6.log.error(`Shader compilation error`, shaderLog)();
566
+ this.device.reportError(new Error(`Shader compilation error`), this, shaderLog)();
567
+ this.device.debug();
495
568
  }
496
569
  }
497
570
  destroy() {
@@ -527,6 +600,9 @@ var __exports__ = (() => {
527
600
  const depthStencil = addDepthStencil(descriptor);
528
601
  return depthStencil.stencilBack;
529
602
  }
603
+ function notSupported(key, value, descriptor) {
604
+ import_core7.log.warn(`${key} parameter not supported in WebGPU`)();
605
+ }
530
606
  function applyParametersToRenderPipelineDescriptor(pipelineDescriptor, parameters = {}) {
531
607
  Object.assign(pipelineDescriptor, { ...DEFAULT_PIPELINE_DESCRIPTOR, ...pipelineDescriptor });
532
608
  setParameters(pipelineDescriptor, parameters);
@@ -534,31 +610,33 @@ var __exports__ = (() => {
534
610
  function setParameters(pipelineDescriptor, parameters) {
535
611
  for (const [key, value] of Object.entries(parameters)) {
536
612
  const setterFunction = PARAMETER_TABLE[key];
537
- if (!setterFunction) {
538
- throw new Error(`Illegal parameter ${key}`);
613
+ if (setterFunction) {
614
+ setterFunction(key, value, pipelineDescriptor);
615
+ } else {
616
+ import_core7.log.error(`Illegal parameter ${key} in WebGPU`)();
539
617
  }
540
- setterFunction(key, value, pipelineDescriptor);
541
618
  }
542
619
  }
543
620
  function addColorState(descriptor, attachment) {
544
621
  descriptor.fragment.targets = descriptor.fragment?.targets || [];
545
622
  if (!Array.isArray(descriptor.fragment?.targets)) {
546
- throw new Error("colorstate");
623
+ import_core7.log.warn("parameters: no targets array")();
547
624
  }
548
625
  if (descriptor.fragment?.targets?.length === 0) {
549
626
  descriptor.fragment.targets?.push({});
550
627
  }
551
- return descriptor.fragment?.targets[0];
628
+ return descriptor.fragment?.targets?.[0];
552
629
  }
553
630
  function addBlendState(descriptor, attachment) {
554
631
  const target = addColorState(descriptor, attachment);
555
632
  target.blend = target.blend || { color: {}, alpha: {} };
556
633
  return target.blend;
557
634
  }
558
- var PARAMETER_TABLE, DEFAULT_PIPELINE_DESCRIPTOR;
635
+ var import_core7, PARAMETER_TABLE, DEFAULT_PIPELINE_DESCRIPTOR;
559
636
  var init_webgpu_parameters = __esm({
560
637
  "src/adapter/helpers/webgpu-parameters.ts"() {
561
638
  "use strict";
639
+ import_core7 = __toESM(require_core(), 1);
562
640
  PARAMETER_TABLE = {
563
641
  // RASTERIZATION PARAMETERS
564
642
  cullMode: (_, value, descriptor) => {
@@ -680,7 +758,19 @@ var __exports__ = (() => {
680
758
  const blend = addBlendState(descriptor, 0);
681
759
  blend.alpha = blend.alpha || {};
682
760
  blend.alpha.dstFactor = value;
683
- }
761
+ },
762
+ unclippedDepth: notSupported,
763
+ provokingVertex: notSupported,
764
+ polygonMode: notSupported,
765
+ polygonOffsetLine: notSupported,
766
+ clipDistance0: notSupported,
767
+ clipDistance1: notSupported,
768
+ clipDistance2: notSupported,
769
+ clipDistance3: notSupported,
770
+ clipDistance4: notSupported,
771
+ clipDistance5: notSupported,
772
+ clipDistance6: notSupported,
773
+ clipDistance7: notSupported
684
774
  };
685
775
  DEFAULT_PIPELINE_DESCRIPTOR = {
686
776
  // depthStencil: {
@@ -720,17 +810,17 @@ var __exports__ = (() => {
720
810
  });
721
811
  device.popErrorScope().then((error) => {
722
812
  if (error) {
723
- import_core7.log.error(`createBindGroup validation failed: ${error.message}`)();
813
+ import_core8.log.error(`bindGroup creation: ${error.message}`, bindGroup)();
724
814
  }
725
815
  });
726
816
  return bindGroup;
727
817
  }
728
818
  function getShaderLayoutBinding(shaderLayout, bindingName, options) {
729
819
  const bindingLayout = shaderLayout.bindings.find(
730
- (binding) => binding.name === bindingName || `${binding.name}uniforms` === bindingName.toLocaleLowerCase()
820
+ (binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
731
821
  );
732
822
  if (!bindingLayout && !options?.ignoreWarnings) {
733
- import_core7.log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
823
+ import_core8.log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
734
824
  }
735
825
  return bindingLayout || null;
736
826
  }
@@ -744,7 +834,7 @@ var __exports__ = (() => {
744
834
  entries.push(entry);
745
835
  }
746
836
  }
747
- if (value instanceof import_core7.Texture) {
837
+ if (value instanceof import_core8.Texture) {
748
838
  bindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
749
839
  ignoreWarnings: true
750
840
  });
@@ -759,7 +849,7 @@ var __exports__ = (() => {
759
849
  return entries;
760
850
  }
761
851
  function getBindGroupEntry(binding, index, options) {
762
- if (binding instanceof import_core7.Buffer) {
852
+ if (binding instanceof import_core8.Buffer) {
763
853
  return {
764
854
  binding: index,
765
855
  resource: {
@@ -767,13 +857,13 @@ var __exports__ = (() => {
767
857
  }
768
858
  };
769
859
  }
770
- if (binding instanceof import_core7.Sampler) {
860
+ if (binding instanceof import_core8.Sampler) {
771
861
  return {
772
862
  binding: index,
773
863
  resource: binding.handle
774
864
  };
775
865
  }
776
- if (binding instanceof import_core7.Texture) {
866
+ if (binding instanceof import_core8.Texture) {
777
867
  if (options?.sampler) {
778
868
  return {
779
869
  binding: index,
@@ -785,14 +875,14 @@ var __exports__ = (() => {
785
875
  resource: binding.view.handle
786
876
  };
787
877
  }
788
- import_core7.log.warn(`invalid binding ${name}`, binding);
878
+ import_core8.log.warn(`invalid binding ${name}`, binding);
789
879
  return null;
790
880
  }
791
- var import_core7;
881
+ var import_core8;
792
882
  var init_get_bind_group = __esm({
793
883
  "src/adapter/helpers/get-bind-group.ts"() {
794
884
  "use strict";
795
- import_core7 = __toESM(require_core(), 1);
885
+ import_core8 = __toESM(require_core(), 1);
796
886
  }
797
887
  });
798
888
 
@@ -810,26 +900,27 @@ var __exports__ = (() => {
810
900
  const vertexAttributes = [];
811
901
  let stepMode = "vertex";
812
902
  let byteStride = 0;
813
- const format = mapping.format;
903
+ let format = mapping.format;
814
904
  if (mapping.attributes) {
815
905
  for (const attributeMapping of mapping.attributes) {
816
906
  const attributeName = attributeMapping.attribute;
817
907
  const attributeLayout = findAttributeLayout(shaderLayout, attributeName, usedAttributes);
818
908
  const location = attributeLayout?.location;
909
+ format = attributeMapping.format || mapping.format;
819
910
  stepMode = attributeLayout?.stepMode || (attributeLayout?.name.startsWith("instance") ? "instance" : "vertex");
820
911
  vertexAttributes.push({
821
- format: getWebGPUVertexFormat(attributeMapping.format || mapping.format),
912
+ format: getWebGPUVertexFormat(format),
822
913
  offset: attributeMapping.byteOffset,
823
914
  shaderLocation: location
824
915
  });
825
- byteStride += (0, import_core8.getVertexFormatInfo)(format).byteLength;
916
+ byteStride += (0, import_core9.getVertexFormatInfo)(format).byteLength;
826
917
  }
827
918
  } else {
828
919
  const attributeLayout = findAttributeLayout(shaderLayout, mapping.name, usedAttributes);
829
920
  if (!attributeLayout) {
830
921
  continue;
831
922
  }
832
- byteStride = (0, import_core8.getVertexFormatInfo)(format).byteLength;
923
+ byteStride = (0, import_core9.getVertexFormatInfo)(format).byteLength;
833
924
  stepMode = attributeLayout.stepMode || (attributeLayout.name.startsWith("instance") ? "instance" : "vertex");
834
925
  vertexAttributes.push({
835
926
  format: getWebGPUVertexFormat(format),
@@ -847,7 +938,7 @@ var __exports__ = (() => {
847
938
  for (const attribute of shaderLayout.attributes) {
848
939
  if (!usedAttributes.has(attribute.name)) {
849
940
  vertexBufferLayouts.push({
850
- arrayStride: (0, import_core8.getVertexFormatInfo)("float32x3").byteLength,
941
+ arrayStride: (0, import_core9.getVertexFormatInfo)("float32x3").byteLength,
851
942
  stepMode: attribute.stepMode || (attribute.name.startsWith("instance") ? "instance" : "vertex"),
852
943
  attributes: [
853
944
  {
@@ -859,39 +950,46 @@ var __exports__ = (() => {
859
950
  });
860
951
  }
861
952
  }
953
+ vertexBufferLayouts.sort((a, b) => {
954
+ const minLocationA = Math.min(...Array.from(a.attributes, (attr) => attr.shaderLocation));
955
+ const minLocationB = Math.min(...Array.from(b.attributes, (attr) => attr.shaderLocation));
956
+ return minLocationA - minLocationB;
957
+ });
862
958
  return vertexBufferLayouts;
863
959
  }
864
960
  function findAttributeLayout(shaderLayout, name2, attributeNames) {
865
961
  const attribute = shaderLayout.attributes.find((attribute_) => attribute_.name === name2);
866
962
  if (!attribute) {
867
- import_core8.log.warn(`Supplied attribute not present in shader layout: ${name2}`)();
963
+ import_core9.log.warn(`Supplied attribute not present in shader layout: ${name2}`)();
868
964
  return null;
869
965
  }
870
- if (attributeNames.has(name2)) {
871
- throw new Error(`Found multiple entries for attribute: ${name2}`);
966
+ if (attributeNames) {
967
+ if (attributeNames.has(name2)) {
968
+ throw new Error(`Found multiple entries for attribute: ${name2}`);
969
+ }
970
+ attributeNames.add(name2);
872
971
  }
873
- attributeNames.add(name2);
874
972
  return attribute;
875
973
  }
876
- var import_core8;
974
+ var import_core9;
877
975
  var init_get_vertex_buffer_layout = __esm({
878
976
  "src/adapter/helpers/get-vertex-buffer-layout.ts"() {
879
977
  "use strict";
880
- import_core8 = __toESM(require_core(), 1);
978
+ import_core9 = __toESM(require_core(), 1);
881
979
  }
882
980
  });
883
981
 
884
982
  // src/adapter/resources/webgpu-render-pipeline.ts
885
- var import_core9, WebGPURenderPipeline;
983
+ var import_core10, WebGPURenderPipeline;
886
984
  var init_webgpu_render_pipeline = __esm({
887
985
  "src/adapter/resources/webgpu-render-pipeline.ts"() {
888
986
  "use strict";
889
- import_core9 = __toESM(require_core(), 1);
987
+ import_core10 = __toESM(require_core(), 1);
890
988
  init_webgpu_parameters();
891
989
  init_convert_texture_format();
892
990
  init_get_bind_group();
893
991
  init_get_vertex_buffer_layout();
894
- WebGPURenderPipeline = class extends import_core9.RenderPipeline {
992
+ WebGPURenderPipeline = class extends import_core10.RenderPipeline {
895
993
  device;
896
994
  handle;
897
995
  vs;
@@ -909,16 +1007,15 @@ var __exports__ = (() => {
909
1007
  this.handle = this.props.handle;
910
1008
  if (!this.handle) {
911
1009
  const descriptor = this._getRenderPipelineDescriptor();
912
- import_core9.log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
913
- import_core9.log.probe(1, JSON.stringify(descriptor, null, 2))();
914
- import_core9.log.groupEnd(1)();
915
- this.device.handle.pushErrorScope("validation");
1010
+ import_core10.log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
1011
+ import_core10.log.probe(1, JSON.stringify(descriptor, null, 2))();
1012
+ import_core10.log.groupEnd(1)();
1013
+ this.device.pushErrorScope("validation");
916
1014
  this.handle = this.device.handle.createRenderPipeline(descriptor);
917
- this.device.handle.popErrorScope().then((error) => {
918
- if (error) {
919
- import_core9.log.error(`${this} creation failed:
920
- "${error.message}"`, this, this.props.vs?.source)();
921
- }
1015
+ this.device.popErrorScope((error) => {
1016
+ this.device.reportError(new Error(`${this} creation failed:
1017
+ "${error.message}"`), this)();
1018
+ this.device.debug();
922
1019
  });
923
1020
  }
924
1021
  this.handle.label = this.props.id;
@@ -944,13 +1041,12 @@ var __exports__ = (() => {
944
1041
  /** @todo - should this be moved to renderpass? */
945
1042
  draw(options) {
946
1043
  const webgpuRenderPass = options.renderPass;
947
- this.device.handle.pushErrorScope("validation");
1044
+ this.device.pushErrorScope("validation");
948
1045
  webgpuRenderPass.handle.setPipeline(this.handle);
949
- this.device.handle.popErrorScope().then((error) => {
950
- if (error) {
951
- import_core9.log.error(`${this} setPipeline failed:
952
- "${error.message}"`, this)();
953
- }
1046
+ this.device.popErrorScope((error) => {
1047
+ this.device.reportError(new Error(`${this} setPipeline failed:
1048
+ "${error.message}"`), this)();
1049
+ this.device.debug();
954
1050
  });
955
1051
  const bindGroup = this._getBindGroup();
956
1052
  if (bindGroup) {
@@ -1007,13 +1103,16 @@ var __exports__ = (() => {
1007
1103
  entryPoint: this.props.fragmentEntryPoint || "main",
1008
1104
  targets
1009
1105
  };
1106
+ const layout = this.device.createPipelineLayout({
1107
+ shaderLayout: this.shaderLayout
1108
+ });
1010
1109
  const descriptor = {
1011
1110
  vertex,
1012
1111
  fragment,
1013
1112
  primitive: {
1014
1113
  topology: this.props.topology
1015
1114
  },
1016
- layout: "auto"
1115
+ layout: layout.handle
1017
1116
  };
1018
1117
  const depthFormat = this.props.depthStencilAttachmentFormat || this.device.preferredDepthFormat;
1019
1118
  if (this.props.parameters.depthWriteEnabled) {
@@ -1029,13 +1128,14 @@ var __exports__ = (() => {
1029
1128
  });
1030
1129
 
1031
1130
  // src/adapter/resources/webgpu-framebuffer.ts
1032
- var import_core10, WebGPUFramebuffer;
1131
+ var import_core11, WebGPUFramebuffer;
1033
1132
  var init_webgpu_framebuffer = __esm({
1034
1133
  "src/adapter/resources/webgpu-framebuffer.ts"() {
1035
1134
  "use strict";
1036
- import_core10 = __toESM(require_core(), 1);
1037
- WebGPUFramebuffer = class extends import_core10.Framebuffer {
1135
+ import_core11 = __toESM(require_core(), 1);
1136
+ WebGPUFramebuffer = class extends import_core11.Framebuffer {
1038
1137
  device;
1138
+ handle = null;
1039
1139
  colorAttachments = [];
1040
1140
  depthStencilAttachment = null;
1041
1141
  constructor(device, props) {
@@ -1050,13 +1150,13 @@ var __exports__ = (() => {
1050
1150
  });
1051
1151
 
1052
1152
  // src/adapter/resources/webgpu-compute-pipeline.ts
1053
- var import_core11, WebGPUComputePipeline;
1153
+ var import_core12, WebGPUComputePipeline;
1054
1154
  var init_webgpu_compute_pipeline = __esm({
1055
1155
  "src/adapter/resources/webgpu-compute-pipeline.ts"() {
1056
1156
  "use strict";
1057
- import_core11 = __toESM(require_core(), 1);
1157
+ import_core12 = __toESM(require_core(), 1);
1058
1158
  init_get_bind_group();
1059
- WebGPUComputePipeline = class extends import_core11.ComputePipeline {
1159
+ WebGPUComputePipeline = class extends import_core12.ComputePipeline {
1060
1160
  device;
1061
1161
  handle;
1062
1162
  /** For internal use to create BindGroups */
@@ -1176,13 +1276,13 @@ var __exports__ = (() => {
1176
1276
  });
1177
1277
 
1178
1278
  // src/adapter/resources/webgpu-vertex-array.ts
1179
- var import_core12, WebGPUVertexArray;
1279
+ var import_core13, WebGPUVertexArray;
1180
1280
  var init_webgpu_vertex_array = __esm({
1181
1281
  "src/adapter/resources/webgpu-vertex-array.ts"() {
1182
1282
  "use strict";
1183
- import_core12 = __toESM(require_core(), 1);
1283
+ import_core13 = __toESM(require_core(), 1);
1184
1284
  init_dist();
1185
- WebGPUVertexArray = class extends import_core12.VertexArray {
1285
+ WebGPUVertexArray = class extends import_core13.VertexArray {
1186
1286
  get [Symbol.toStringTag]() {
1187
1287
  return "WebGPUVertexArray";
1188
1288
  }
@@ -1211,7 +1311,7 @@ var __exports__ = (() => {
1211
1311
  const webgpuRenderPass = renderPass;
1212
1312
  const webgpuIndexBuffer = this.indexBuffer;
1213
1313
  if (webgpuIndexBuffer?.handle) {
1214
- import_core12.log.info(
1314
+ import_core13.log.info(
1215
1315
  3,
1216
1316
  "setting index buffer",
1217
1317
  webgpuIndexBuffer?.handle,
@@ -1226,7 +1326,7 @@ var __exports__ = (() => {
1226
1326
  for (let location = 0; location < this.maxVertexAttributes; location++) {
1227
1327
  const webgpuBuffer = this.attributes[location];
1228
1328
  if (webgpuBuffer?.handle) {
1229
- import_core12.log.info(3, `setting vertex buffer ${location}`, webgpuBuffer?.handle)();
1329
+ import_core13.log.info(3, `setting vertex buffer ${location}`, webgpuBuffer?.handle)();
1230
1330
  webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer?.handle);
1231
1331
  }
1232
1332
  }
@@ -1246,13 +1346,13 @@ var __exports__ = (() => {
1246
1346
  });
1247
1347
 
1248
1348
  // src/adapter/webgpu-canvas-context.ts
1249
- var import_core13, WebGPUCanvasContext;
1349
+ var import_core14, WebGPUCanvasContext;
1250
1350
  var init_webgpu_canvas_context = __esm({
1251
1351
  "src/adapter/webgpu-canvas-context.ts"() {
1252
1352
  "use strict";
1253
- import_core13 = __toESM(require_core(), 1);
1353
+ import_core14 = __toESM(require_core(), 1);
1254
1354
  init_webgpu_framebuffer();
1255
- WebGPUCanvasContext = class extends import_core13.CanvasContext {
1355
+ WebGPUCanvasContext = class extends import_core14.CanvasContext {
1256
1356
  device;
1257
1357
  handle;
1258
1358
  depthStencilAttachment = null;
@@ -1273,6 +1373,7 @@ var __exports__ = (() => {
1273
1373
  /** Destroy any textures produced while configured and remove the context configuration. */
1274
1374
  destroy() {
1275
1375
  this.handle.unconfigure();
1376
+ super.destroy();
1276
1377
  }
1277
1378
  /** Update framebuffer with properly resized "swap chain" texture views */
1278
1379
  getCurrentFramebuffer(options = {
@@ -1283,7 +1384,7 @@ var __exports__ = (() => {
1283
1384
  const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1284
1385
  this.drawingBufferWidth = currentColorAttachment.width;
1285
1386
  this.drawingBufferHeight = currentColorAttachment.height;
1286
- import_core13.log.log(
1387
+ import_core14.log.log(
1287
1388
  1,
1288
1389
  `${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`
1289
1390
  )();
@@ -1327,7 +1428,7 @@ var __exports__ = (() => {
1327
1428
  if (!this.depthStencilAttachment) {
1328
1429
  this.depthStencilAttachment = this.device.createTexture({
1329
1430
  id: `${this.id}#depth-stencil-texture`,
1330
- usage: import_core13.Texture.RENDER_ATTACHMENT,
1431
+ usage: import_core14.Texture.RENDER_ATTACHMENT,
1331
1432
  format: depthStencilFormat,
1332
1433
  width: this.drawingBufferWidth,
1333
1434
  height: this.drawingBufferHeight
@@ -1340,12 +1441,12 @@ var __exports__ = (() => {
1340
1441
  });
1341
1442
 
1342
1443
  // src/adapter/resources/webgpu-command-buffer.ts
1343
- var import_core14, WebGPUCommandBuffer;
1444
+ var import_core15, WebGPUCommandBuffer;
1344
1445
  var init_webgpu_command_buffer = __esm({
1345
1446
  "src/adapter/resources/webgpu-command-buffer.ts"() {
1346
1447
  "use strict";
1347
- import_core14 = __toESM(require_core(), 1);
1348
- WebGPUCommandBuffer = class extends import_core14.CommandBuffer {
1448
+ import_core15 = __toESM(require_core(), 1);
1449
+ WebGPUCommandBuffer = class extends import_core15.CommandBuffer {
1349
1450
  device;
1350
1451
  handle;
1351
1452
  constructor(commandEncoder, props) {
@@ -1360,12 +1461,15 @@ var __exports__ = (() => {
1360
1461
  });
1361
1462
 
1362
1463
  // src/adapter/resources/webgpu-render-pass.ts
1363
- var import_core15, WebGPURenderPass;
1464
+ function convertColor(color) {
1465
+ return { r: color[0], g: color[1], b: color[2], a: color[3] };
1466
+ }
1467
+ var import_core16, WebGPURenderPass;
1364
1468
  var init_webgpu_render_pass = __esm({
1365
1469
  "src/adapter/resources/webgpu-render-pass.ts"() {
1366
1470
  "use strict";
1367
- import_core15 = __toESM(require_core(), 1);
1368
- WebGPURenderPass = class extends import_core15.RenderPass {
1471
+ import_core16 = __toESM(require_core(), 1);
1472
+ WebGPURenderPass = class extends import_core16.RenderPass {
1369
1473
  device;
1370
1474
  handle;
1371
1475
  /** Active pipeline */
@@ -1390,18 +1494,17 @@ var __exports__ = (() => {
1390
1494
  if (!device.commandEncoder) {
1391
1495
  throw new Error("commandEncoder not available");
1392
1496
  }
1393
- this.device.handle.pushErrorScope("validation");
1497
+ this.device.pushErrorScope("validation");
1394
1498
  this.handle = this.props.handle || device.commandEncoder.handle.beginRenderPass(renderPassDescriptor);
1395
- this.device.handle.popErrorScope().then((error) => {
1396
- if (error) {
1397
- import_core15.log.error(`${this} creation failed:
1398
- "${error.message}"`, this)();
1399
- }
1499
+ this.device.popErrorScope((error) => {
1500
+ this.device.reportError(new Error(`${this} creation failed:
1501
+ "${error.message}"`), this)();
1502
+ this.device.debug();
1400
1503
  });
1401
1504
  this.handle.label = this.props.id;
1402
- import_core15.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1403
- import_core15.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1404
- import_core15.log.groupEnd(3)();
1505
+ import_core16.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1506
+ import_core16.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1507
+ import_core16.log.groupEnd(3)();
1405
1508
  }
1406
1509
  destroy() {
1407
1510
  }
@@ -1410,7 +1513,13 @@ var __exports__ = (() => {
1410
1513
  }
1411
1514
  setPipeline(pipeline) {
1412
1515
  this.pipeline = pipeline;
1516
+ this.device.pushErrorScope("validation");
1413
1517
  this.handle.setPipeline(this.pipeline.handle);
1518
+ this.device.popErrorScope((error) => {
1519
+ this.device.reportError(new Error(`${this} setPipeline failed:
1520
+ "${error.message}"`), this)();
1521
+ this.device.debug();
1522
+ });
1414
1523
  }
1415
1524
  /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
1416
1525
  setBindings(bindings) {
@@ -1463,8 +1572,8 @@ var __exports__ = (() => {
1463
1572
  viewport[1],
1464
1573
  viewport[2],
1465
1574
  viewport[3],
1466
- viewport[4],
1467
- viewport[5]
1575
+ viewport[4] ?? 0,
1576
+ viewport[5] ?? 1
1468
1577
  );
1469
1578
  }
1470
1579
  }
@@ -1497,7 +1606,9 @@ var __exports__ = (() => {
1497
1606
  (colorAttachment, index) => ({
1498
1607
  // clear values
1499
1608
  loadOp: this.props.clearColor !== false ? "clear" : "load",
1500
- colorClearValue: this.props.clearColors?.[index] || this.props.clearColor || import_core15.RenderPass.defaultClearColor,
1609
+ clearValue: convertColor(
1610
+ this.props.clearColors?.[index] || this.props.clearColor || import_core16.RenderPass.defaultClearColor
1611
+ ),
1501
1612
  storeOp: this.props.discard ? "discard" : "store",
1502
1613
  // ...colorAttachment,
1503
1614
  view: colorAttachment.handle
@@ -1532,12 +1643,12 @@ var __exports__ = (() => {
1532
1643
  });
1533
1644
 
1534
1645
  // src/adapter/resources/webgpu-compute-pass.ts
1535
- var import_core16, WebGPUComputePass;
1646
+ var import_core17, WebGPUComputePass;
1536
1647
  var init_webgpu_compute_pass = __esm({
1537
1648
  "src/adapter/resources/webgpu-compute-pass.ts"() {
1538
1649
  "use strict";
1539
- import_core16 = __toESM(require_core(), 1);
1540
- WebGPUComputePass = class extends import_core16.ComputePass {
1650
+ import_core17 = __toESM(require_core(), 1);
1651
+ WebGPUComputePass = class extends import_core17.ComputePass {
1541
1652
  device;
1542
1653
  handle;
1543
1654
  _webgpuPipeline = null;
@@ -1614,15 +1725,15 @@ var __exports__ = (() => {
1614
1725
  });
1615
1726
 
1616
1727
  // src/adapter/resources/webgpu-command-encoder.ts
1617
- var import_core17, WebGPUCommandEncoder;
1728
+ var import_core18, WebGPUCommandEncoder;
1618
1729
  var init_webgpu_command_encoder = __esm({
1619
1730
  "src/adapter/resources/webgpu-command-encoder.ts"() {
1620
1731
  "use strict";
1621
- import_core17 = __toESM(require_core(), 1);
1732
+ import_core18 = __toESM(require_core(), 1);
1622
1733
  init_webgpu_command_buffer();
1623
1734
  init_webgpu_render_pass();
1624
1735
  init_webgpu_compute_pass();
1625
- WebGPUCommandEncoder = class extends import_core17.CommandEncoder {
1736
+ WebGPUCommandEncoder = class extends import_core18.CommandEncoder {
1626
1737
  device;
1627
1738
  handle;
1628
1739
  constructor(device, props = {}) {
@@ -1638,9 +1749,16 @@ var __exports__ = (() => {
1638
1749
  destroy() {
1639
1750
  }
1640
1751
  finish(props) {
1641
- return new WebGPUCommandBuffer(this, {
1752
+ this.device.pushErrorScope("validation");
1753
+ const commandBuffer = new WebGPUCommandBuffer(this, {
1642
1754
  id: props?.id || "unnamed-command-buffer"
1643
1755
  });
1756
+ this.device.popErrorScope((error) => {
1757
+ const message = `${this} command encoding: ${error.message}. Maybe add depthWriteEnabled to your Model?`;
1758
+ this.device.reportError(new Error(message), this)();
1759
+ this.device.debug();
1760
+ });
1761
+ return commandBuffer;
1644
1762
  }
1645
1763
  /**
1646
1764
  * Allows a render pass to begin against a canvas context
@@ -1718,12 +1836,12 @@ var __exports__ = (() => {
1718
1836
  });
1719
1837
 
1720
1838
  // src/adapter/resources/webgpu-query-set.ts
1721
- var import_core18, WebGPUQuerySet;
1839
+ var import_core19, WebGPUQuerySet;
1722
1840
  var init_webgpu_query_set = __esm({
1723
1841
  "src/adapter/resources/webgpu-query-set.ts"() {
1724
1842
  "use strict";
1725
- import_core18 = __toESM(require_core(), 1);
1726
- WebGPUQuerySet = class extends import_core18.QuerySet {
1843
+ import_core19 = __toESM(require_core(), 1);
1844
+ WebGPUQuerySet = class extends import_core19.QuerySet {
1727
1845
  device;
1728
1846
  handle;
1729
1847
  constructor(device, props) {
@@ -1743,16 +1861,119 @@ var __exports__ = (() => {
1743
1861
  }
1744
1862
  });
1745
1863
 
1864
+ // src/adapter/resources/webgpu-pipeline-layout.ts
1865
+ var import_core20, WebGPUPipelineLayout, isStorageTextureBindingLayout;
1866
+ var init_webgpu_pipeline_layout = __esm({
1867
+ "src/adapter/resources/webgpu-pipeline-layout.ts"() {
1868
+ "use strict";
1869
+ import_core20 = __toESM(require_core(), 1);
1870
+ WebGPUPipelineLayout = class extends import_core20.PipelineLayout {
1871
+ device;
1872
+ handle;
1873
+ constructor(device, props) {
1874
+ super(device, props);
1875
+ this.device = device;
1876
+ const bindGroupEntries = this.mapShaderLayoutToBindGroupEntries();
1877
+ this.handle = this.device.handle.createPipelineLayout({
1878
+ label: props?.id ?? "unnamed-pipeline-layout",
1879
+ bindGroupLayouts: [
1880
+ // TODO (kaapp): We can cache these to re-use them across
1881
+ // layers, particularly if using a separate group for injected
1882
+ // bindings (e.g. project/lighting)
1883
+ this.device.handle.createBindGroupLayout({
1884
+ label: "bind-group-layout",
1885
+ entries: bindGroupEntries
1886
+ })
1887
+ ]
1888
+ });
1889
+ }
1890
+ destroy() {
1891
+ this.handle = null;
1892
+ }
1893
+ mapShaderLayoutToBindGroupEntries() {
1894
+ const bindGroupEntries = [];
1895
+ for (let i = 0; i < this.props.shaderLayout.bindings.length; i++) {
1896
+ const binding = this.props.shaderLayout.bindings[i];
1897
+ const bindingTypeInfo = {};
1898
+ switch (binding.type) {
1899
+ case "uniform": {
1900
+ bindingTypeInfo.buffer = {
1901
+ type: "uniform",
1902
+ hasDynamicOffset: binding.hasDynamicOffset,
1903
+ minBindingSize: binding.minBindingSize
1904
+ };
1905
+ break;
1906
+ }
1907
+ case "read-only-storage": {
1908
+ bindingTypeInfo.buffer = {
1909
+ type: "read-only-storage",
1910
+ hasDynamicOffset: binding.hasDynamicOffset,
1911
+ minBindingSize: binding.minBindingSize
1912
+ };
1913
+ break;
1914
+ }
1915
+ case "sampler": {
1916
+ bindingTypeInfo.sampler = {
1917
+ type: binding.samplerType
1918
+ };
1919
+ break;
1920
+ }
1921
+ case "storage": {
1922
+ if (isStorageTextureBindingLayout(binding)) {
1923
+ bindingTypeInfo.storageTexture = {
1924
+ // TODO (kaapp): Not all formats in the binding layout are supported
1925
+ // by WebGPU, but at least it will provide a clear error for now.
1926
+ format: binding.format,
1927
+ access: binding.access,
1928
+ viewDimension: binding.viewDimension
1929
+ };
1930
+ } else {
1931
+ bindingTypeInfo.buffer = {
1932
+ type: "storage",
1933
+ hasDynamicOffset: binding.hasDynamicOffset,
1934
+ minBindingSize: binding.minBindingSize
1935
+ };
1936
+ }
1937
+ break;
1938
+ }
1939
+ case "texture": {
1940
+ bindingTypeInfo.texture = {
1941
+ multisampled: binding.multisampled,
1942
+ sampleType: binding.sampleType,
1943
+ viewDimension: binding.viewDimension
1944
+ };
1945
+ break;
1946
+ }
1947
+ default: {
1948
+ import_core20.log.warn("unhandled binding type when creating pipeline descriptor")();
1949
+ }
1950
+ }
1951
+ const VISIBILITY_ALL = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE;
1952
+ bindGroupEntries.push({
1953
+ binding: binding.location,
1954
+ visibility: binding.visibility || VISIBILITY_ALL,
1955
+ ...bindingTypeInfo
1956
+ });
1957
+ }
1958
+ return bindGroupEntries;
1959
+ }
1960
+ };
1961
+ isStorageTextureBindingLayout = (maybe) => {
1962
+ return maybe.format !== void 0;
1963
+ };
1964
+ }
1965
+ });
1966
+
1746
1967
  // src/adapter/webgpu-device.ts
1747
1968
  var webgpu_device_exports = {};
1748
1969
  __export(webgpu_device_exports, {
1749
1970
  WebGPUDevice: () => WebGPUDevice
1750
1971
  });
1751
- var import_core19, WebGPUDevice;
1972
+ var import_core21, WebGPUDevice;
1752
1973
  var init_webgpu_device = __esm({
1753
1974
  "src/adapter/webgpu-device.ts"() {
1754
1975
  "use strict";
1755
- import_core19 = __toESM(require_core(), 1);
1976
+ import_core21 = __toESM(require_core(), 1);
1756
1977
  init_webgpu_buffer();
1757
1978
  init_webgpu_texture();
1758
1979
  init_webgpu_external_texture();
@@ -1765,9 +1986,14 @@ var __exports__ = (() => {
1765
1986
  init_webgpu_canvas_context();
1766
1987
  init_webgpu_command_encoder();
1767
1988
  init_webgpu_query_set();
1768
- WebGPUDevice = class extends import_core19.Device {
1989
+ init_webgpu_pipeline_layout();
1990
+ WebGPUDevice = class extends import_core21.Device {
1769
1991
  /** The underlying WebGPU device */
1770
1992
  handle;
1993
+ /* The underlying WebGPU adapter */
1994
+ adapter;
1995
+ /* The underlying WebGPU adapter's info */
1996
+ adapterInfo;
1771
1997
  /** type of this device */
1772
1998
  type = "webgpu";
1773
1999
  preferredColorFormat = navigator.gpu.getPreferredCanvasFormat();
@@ -1779,10 +2005,12 @@ var __exports__ = (() => {
1779
2005
  canvasContext = null;
1780
2006
  _isLost = false;
1781
2007
  commandEncoder;
1782
- /* The underlying WebGPU adapter */
1783
- adapter;
1784
- /* The underlying WebGPU adapter's info */
1785
- adapterInfo;
2008
+ get [Symbol.toStringTag]() {
2009
+ return "WebGPUDevice";
2010
+ }
2011
+ toString() {
2012
+ return `WebGPUDevice(${this.id})`;
2013
+ }
1786
2014
  constructor(props, device, adapter, adapterInfo) {
1787
2015
  super({ ...props, id: props.id || "webgpu-device" });
1788
2016
  this.handle = device;
@@ -1794,18 +2022,16 @@ var __exports__ = (() => {
1794
2022
  device.addEventListener("uncapturederror", (event) => {
1795
2023
  event.preventDefault();
1796
2024
  const errorMessage = event instanceof GPUUncapturedErrorEvent ? event.error.message : "Unknown WebGPU error";
1797
- this.reportError(new Error(errorMessage));
1798
- if (this.props.debug) {
1799
- debugger;
1800
- }
2025
+ this.reportError(new Error(errorMessage), this)();
2026
+ this.debug();
1801
2027
  });
1802
2028
  this.lost = new Promise(async (resolve) => {
1803
2029
  const lostInfo = await this.handle.lost;
1804
2030
  this._isLost = true;
1805
2031
  resolve({ reason: "destroyed", message: lostInfo.message });
1806
2032
  });
1807
- if (props.createCanvasContext) {
1808
- const canvasContextProps = props.createCanvasContext === true ? {} : props.createCanvasContext;
2033
+ const canvasContextProps = import_core21.Device._getCanvasContextProps(props);
2034
+ if (canvasContextProps) {
1809
2035
  this.canvasContext = new WebGPUCanvasContext(this, this.adapter, canvasContextProps);
1810
2036
  }
1811
2037
  this.commandEncoder = this.createCommandEncoder({});
@@ -1820,6 +2046,13 @@ var __exports__ = (() => {
1820
2046
  get isLost() {
1821
2047
  return this._isLost;
1822
2048
  }
2049
+ isVertexFormatSupported(format) {
2050
+ const info = this.getVertexFormatInfo(format);
2051
+ return !info.webglOnly;
2052
+ }
2053
+ getTextureByteAlignment() {
2054
+ return 1;
2055
+ }
1823
2056
  createBuffer(props) {
1824
2057
  const newProps = this._normalizeBufferProps(props);
1825
2058
  return new WebGPUBuffer(this, newProps);
@@ -1861,18 +2094,20 @@ var __exports__ = (() => {
1861
2094
  createCanvasContext(props) {
1862
2095
  return new WebGPUCanvasContext(this, this.adapter, props);
1863
2096
  }
2097
+ createPipelineLayout(props) {
2098
+ return new WebGPUPipelineLayout(this, props);
2099
+ }
1864
2100
  submit(commandBuffer) {
1865
2101
  if (!commandBuffer) {
1866
2102
  commandBuffer = this.commandEncoder.finish();
1867
2103
  this.commandEncoder.destroy();
1868
2104
  this.commandEncoder = this.createCommandEncoder({ id: `${this.id}-default-encoder` });
1869
2105
  }
1870
- this.handle.pushErrorScope("validation");
2106
+ this.pushErrorScope("validation");
1871
2107
  this.handle.queue.submit([commandBuffer.handle]);
1872
- this.handle.popErrorScope().then((error) => {
1873
- if (error) {
1874
- this.reportError(new Error(`WebGPU command submission failed: ${error.message}`));
1875
- }
2108
+ this.popErrorScope((error) => {
2109
+ this.reportError(new Error(`${this} command submission: ${error.message}`), this)();
2110
+ this.debug();
1876
2111
  });
1877
2112
  }
1878
2113
  // WebGPU specific
@@ -1882,7 +2117,7 @@ var __exports__ = (() => {
1882
2117
  popErrorScope(handler) {
1883
2118
  this.handle.popErrorScope().then((error) => {
1884
2119
  if (error) {
1885
- handler(error.message);
2120
+ handler(error);
1886
2121
  }
1887
2122
  });
1888
2123
  }
@@ -1930,7 +2165,7 @@ var __exports__ = (() => {
1930
2165
  for (const feature of WEBGPU_ALWAYS_FEATURES) {
1931
2166
  features.add(feature);
1932
2167
  }
1933
- return new import_core19.DeviceFeatures(Array.from(features), this.props._disabledFeatures);
2168
+ return new import_core21.DeviceFeatures(Array.from(features), this.props._disabledFeatures);
1934
2169
  }
1935
2170
  _getDeviceSpecificTextureFormatCapabilities(capabilities) {
1936
2171
  const { format } = capabilities;
@@ -1956,8 +2191,8 @@ var __exports__ = (() => {
1956
2191
  __reExport(bundle_exports, __toESM(require_core(), 1));
1957
2192
 
1958
2193
  // src/adapter/webgpu-adapter.ts
1959
- var import_core20 = __toESM(require_core(), 1);
1960
- var WebGPUAdapter = class extends import_core20.Adapter {
2194
+ var import_core22 = __toESM(require_core(), 1);
2195
+ var WebGPUAdapter = class extends import_core22.Adapter {
1961
2196
  /** type of device's created by this adapter */
1962
2197
  type = "webgpu";
1963
2198
  isSupported() {
@@ -1976,46 +2211,49 @@ var __exports__ = (() => {
1976
2211
  if (!navigator.gpu) {
1977
2212
  throw new Error("WebGPU not available. Recent Chrome browsers should work.");
1978
2213
  }
1979
- import_core20.log.groupCollapsed(1, "WebGPUDevice created")();
1980
- const adapter = await navigator.gpu.requestAdapter({
1981
- powerPreference: "high-performance"
1982
- // forceSoftware: false
1983
- });
1984
- if (!adapter) {
1985
- throw new Error("Failed to request WebGPU adapter");
1986
- }
1987
- const adapterInfo = adapter.info || // @ts-ignore
1988
- await adapter.requestAdapterInfo?.();
1989
- import_core20.log.probe(2, "Adapter available", adapterInfo)();
1990
- const requiredFeatures = [];
1991
- const requiredLimits = {};
1992
- if (props._requestMaxLimits) {
1993
- requiredFeatures.push(...Array.from(adapter.features));
1994
- const limits = Object.keys(adapter.limits).filter(
1995
- (key) => !["minSubgroupSize", "maxSubgroupSize"].includes(key)
1996
- );
1997
- for (const key of limits) {
1998
- const limit = key;
1999
- const value = adapter.limits[limit];
2000
- if (typeof value === "number") {
2001
- requiredLimits[limit] = value;
2214
+ import_core22.log.groupCollapsed(1, "WebGPUDevice created")();
2215
+ try {
2216
+ const adapter = await navigator.gpu.requestAdapter({
2217
+ powerPreference: "high-performance"
2218
+ // forceSoftware: false
2219
+ });
2220
+ if (!adapter) {
2221
+ throw new Error("Failed to request WebGPU adapter");
2222
+ }
2223
+ const adapterInfo = adapter.info || // @ts-ignore
2224
+ await adapter.requestAdapterInfo?.();
2225
+ import_core22.log.probe(2, "Adapter available", adapterInfo)();
2226
+ const requiredFeatures = [];
2227
+ const requiredLimits = {};
2228
+ if (props._requestMaxLimits) {
2229
+ requiredFeatures.push(...Array.from(adapter.features));
2230
+ const limits = Object.keys(adapter.limits).filter(
2231
+ (key) => !["minSubgroupSize", "maxSubgroupSize"].includes(key)
2232
+ );
2233
+ for (const key of limits) {
2234
+ const limit = key;
2235
+ const value = adapter.limits[limit];
2236
+ if (typeof value === "number") {
2237
+ requiredLimits[limit] = value;
2238
+ }
2002
2239
  }
2003
2240
  }
2241
+ const gpuDevice = await adapter.requestDevice({
2242
+ requiredFeatures,
2243
+ requiredLimits
2244
+ });
2245
+ import_core22.log.probe(1, "GPUDevice available")();
2246
+ const { WebGPUDevice: WebGPUDevice2 } = await Promise.resolve().then(() => (init_webgpu_device(), webgpu_device_exports));
2247
+ const device = new WebGPUDevice2(props, gpuDevice, adapter, adapterInfo);
2248
+ import_core22.log.probe(
2249
+ 1,
2250
+ "Device created. For more info, set chrome://flags/#enable-webgpu-developer-features"
2251
+ )();
2252
+ import_core22.log.table(1, device.info)();
2253
+ return device;
2254
+ } finally {
2255
+ import_core22.log.groupEnd(1)();
2004
2256
  }
2005
- const gpuDevice = await adapter.requestDevice({
2006
- requiredFeatures,
2007
- requiredLimits
2008
- });
2009
- import_core20.log.probe(1, "GPUDevice available")();
2010
- const { WebGPUDevice: WebGPUDevice2 } = await Promise.resolve().then(() => (init_webgpu_device(), webgpu_device_exports));
2011
- const device = new WebGPUDevice2(props, gpuDevice, adapter, adapterInfo);
2012
- import_core20.log.probe(
2013
- 1,
2014
- "Device created. For more info, set chrome://flags/#enable-webgpu-developer-features"
2015
- )();
2016
- import_core20.log.table(1, device.info)();
2017
- import_core20.log.groupEnd(1)();
2018
- return device;
2019
2257
  }
2020
2258
  async attach(handle) {
2021
2259
  throw new Error("WebGPUAdapter.attach() not implemented");