@luma.gl/webgpu 9.3.0-alpha.4 → 9.3.0-alpha.6

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 (93) hide show
  1. package/dist/adapter/helpers/cpu-hotspot-profiler.d.ts +54 -0
  2. package/dist/adapter/helpers/cpu-hotspot-profiler.d.ts.map +1 -0
  3. package/dist/adapter/helpers/cpu-hotspot-profiler.js +26 -0
  4. package/dist/adapter/helpers/cpu-hotspot-profiler.js.map +1 -0
  5. package/dist/adapter/helpers/generate-mipmaps-webgpu.d.ts +7 -0
  6. package/dist/adapter/helpers/generate-mipmaps-webgpu.d.ts.map +1 -0
  7. package/dist/adapter/helpers/generate-mipmaps-webgpu.js +490 -0
  8. package/dist/adapter/helpers/generate-mipmaps-webgpu.js.map +1 -0
  9. package/dist/adapter/helpers/get-bind-group.d.ts +2 -1
  10. package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
  11. package/dist/adapter/helpers/get-bind-group.js +22 -18
  12. package/dist/adapter/helpers/get-bind-group.js.map +1 -1
  13. package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
  14. package/dist/adapter/resources/webgpu-buffer.js +19 -3
  15. package/dist/adapter/resources/webgpu-buffer.js.map +1 -1
  16. package/dist/adapter/resources/webgpu-command-buffer.js +1 -1
  17. package/dist/adapter/resources/webgpu-command-buffer.js.map +1 -1
  18. package/dist/adapter/resources/webgpu-command-encoder.d.ts +5 -4
  19. package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
  20. package/dist/adapter/resources/webgpu-command-encoder.js +23 -5
  21. package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -1
  22. package/dist/adapter/resources/webgpu-compute-pass.d.ts +1 -1
  23. package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
  24. package/dist/adapter/resources/webgpu-compute-pass.js +14 -6
  25. package/dist/adapter/resources/webgpu-compute-pass.js.map +1 -1
  26. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
  27. package/dist/adapter/resources/webgpu-compute-pipeline.js +19 -3
  28. package/dist/adapter/resources/webgpu-compute-pipeline.js.map +1 -1
  29. package/dist/adapter/resources/webgpu-framebuffer.d.ts +6 -0
  30. package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -1
  31. package/dist/adapter/resources/webgpu-framebuffer.js +16 -0
  32. package/dist/adapter/resources/webgpu-framebuffer.js.map +1 -1
  33. package/dist/adapter/resources/webgpu-query-set.d.ts +33 -4
  34. package/dist/adapter/resources/webgpu-query-set.d.ts.map +1 -1
  35. package/dist/adapter/resources/webgpu-query-set.js +145 -4
  36. package/dist/adapter/resources/webgpu-query-set.js.map +1 -1
  37. package/dist/adapter/resources/webgpu-render-pass.d.ts +3 -0
  38. package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
  39. package/dist/adapter/resources/webgpu-render-pass.js +74 -30
  40. package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
  41. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +7 -4
  42. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  43. package/dist/adapter/resources/webgpu-render-pipeline.js +26 -15
  44. package/dist/adapter/resources/webgpu-render-pipeline.js.map +1 -1
  45. package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -1
  46. package/dist/adapter/resources/webgpu-sampler.js +4 -0
  47. package/dist/adapter/resources/webgpu-sampler.js.map +1 -1
  48. package/dist/adapter/resources/webgpu-texture-view.d.ts +6 -0
  49. package/dist/adapter/resources/webgpu-texture-view.d.ts.map +1 -1
  50. package/dist/adapter/resources/webgpu-texture-view.js +47 -11
  51. package/dist/adapter/resources/webgpu-texture-view.js.map +1 -1
  52. package/dist/adapter/resources/webgpu-texture.d.ts +10 -4
  53. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  54. package/dist/adapter/resources/webgpu-texture.js +116 -57
  55. package/dist/adapter/resources/webgpu-texture.js.map +1 -1
  56. package/dist/adapter/resources/webgpu-vertex-array.js +1 -1
  57. package/dist/adapter/resources/webgpu-vertex-array.js.map +1 -1
  58. package/dist/adapter/webgpu-canvas-context.d.ts +2 -0
  59. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
  60. package/dist/adapter/webgpu-canvas-context.js +78 -19
  61. package/dist/adapter/webgpu-canvas-context.js.map +1 -1
  62. package/dist/adapter/webgpu-device.d.ts +5 -1
  63. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  64. package/dist/adapter/webgpu-device.js +113 -9
  65. package/dist/adapter/webgpu-device.js.map +1 -1
  66. package/dist/adapter/webgpu-presentation-context.d.ts +25 -0
  67. package/dist/adapter/webgpu-presentation-context.d.ts.map +1 -0
  68. package/dist/adapter/webgpu-presentation-context.js +144 -0
  69. package/dist/adapter/webgpu-presentation-context.js.map +1 -0
  70. package/dist/dist.dev.js +2815 -1681
  71. package/dist/dist.min.js +167 -8
  72. package/dist/index.cjs +1314 -199
  73. package/dist/index.cjs.map +4 -4
  74. package/package.json +4 -4
  75. package/src/adapter/helpers/cpu-hotspot-profiler.ts +70 -0
  76. package/src/adapter/helpers/generate-mipmaps-webgpu.ts +583 -0
  77. package/src/adapter/helpers/get-bind-group.ts +26 -24
  78. package/src/adapter/resources/webgpu-buffer.ts +18 -3
  79. package/src/adapter/resources/webgpu-command-buffer.ts +1 -1
  80. package/src/adapter/resources/webgpu-command-encoder.ts +32 -6
  81. package/src/adapter/resources/webgpu-compute-pass.ts +14 -6
  82. package/src/adapter/resources/webgpu-compute-pipeline.ts +21 -3
  83. package/src/adapter/resources/webgpu-framebuffer.ts +21 -0
  84. package/src/adapter/resources/webgpu-query-set.ts +185 -9
  85. package/src/adapter/resources/webgpu-render-pass.ts +82 -34
  86. package/src/adapter/resources/webgpu-render-pipeline.ts +36 -19
  87. package/src/adapter/resources/webgpu-sampler.ts +5 -0
  88. package/src/adapter/resources/webgpu-texture-view.ts +51 -11
  89. package/src/adapter/resources/webgpu-texture.ts +142 -93
  90. package/src/adapter/resources/webgpu-vertex-array.ts +1 -1
  91. package/src/adapter/webgpu-canvas-context.ts +91 -26
  92. package/src/adapter/webgpu-device.ts +128 -9
  93. package/src/adapter/webgpu-presentation-context.ts +180 -0
package/dist/index.cjs CHANGED
@@ -74,11 +74,24 @@ var init_webgpu_buffer = __esm({
74
74
  this.device.reportError(new Error(`${this} creation failed ${error.message}`), this)();
75
75
  this.device.debug();
76
76
  });
77
+ if (!this.props.handle) {
78
+ this.trackAllocatedMemory(size);
79
+ } else {
80
+ this.trackReferencedMemory(size, "Buffer");
81
+ }
77
82
  }
78
83
  destroy() {
79
- var _a;
80
- (_a = this.handle) == null ? void 0 : _a.destroy();
81
- this.handle = null;
84
+ if (!this.destroyed && this.handle) {
85
+ this.removeStats();
86
+ if (!this.props.handle) {
87
+ this.trackDeallocatedMemory();
88
+ this.handle.destroy();
89
+ } else {
90
+ this.trackDeallocatedReferencedMemory("Buffer");
91
+ }
92
+ this.destroyed = true;
93
+ this.handle = null;
94
+ }
82
95
  }
83
96
  write(data, byteOffset = 0) {
84
97
  const arrayBuffer = ArrayBuffer.isView(data) ? data.buffer : data;
@@ -226,18 +239,47 @@ var init_webgpu_sampler = __esm({
226
239
  this.handle.label = this.props.id;
227
240
  }
228
241
  destroy() {
242
+ if (this.destroyed) {
243
+ return;
244
+ }
245
+ this.destroyResource();
229
246
  this.handle = null;
230
247
  }
231
248
  };
232
249
  }
233
250
  });
234
251
 
252
+ // dist/adapter/helpers/cpu-hotspot-profiler.js
253
+ function getCpuHotspotProfiler(owner) {
254
+ const profiler = owner.userData[CPU_HOTSPOT_PROFILER_MODULE];
255
+ return (profiler == null ? void 0 : profiler.enabled) ? profiler : null;
256
+ }
257
+ function getCpuHotspotSubmitReason(owner) {
258
+ return owner.userData[CPU_HOTSPOT_SUBMIT_REASON] || null;
259
+ }
260
+ function setCpuHotspotSubmitReason(owner, submitReason) {
261
+ owner.userData[CPU_HOTSPOT_SUBMIT_REASON] = submitReason;
262
+ }
263
+ function getTimestamp() {
264
+ var _a, _b;
265
+ return ((_b = (_a = globalThis.performance) == null ? void 0 : _a.now) == null ? void 0 : _b.call(_a)) ?? Date.now();
266
+ }
267
+ var CPU_HOTSPOT_PROFILER_MODULE, CPU_HOTSPOT_SUBMIT_REASON;
268
+ var init_cpu_hotspot_profiler = __esm({
269
+ "dist/adapter/helpers/cpu-hotspot-profiler.js"() {
270
+ "use strict";
271
+ CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
272
+ CPU_HOTSPOT_SUBMIT_REASON = "cpu-hotspot-submit-reason";
273
+ }
274
+ });
275
+
235
276
  // dist/adapter/resources/webgpu-texture-view.js
236
277
  var import_core3, WebGPUTextureView;
237
278
  var init_webgpu_texture_view = __esm({
238
279
  "dist/adapter/resources/webgpu-texture-view.js"() {
239
280
  "use strict";
240
281
  import_core3 = require("@luma.gl/core");
282
+ init_cpu_hotspot_profiler();
241
283
  WebGPUTextureView = class extends import_core3.TextureView {
242
284
  device;
243
285
  handle;
@@ -247,8 +289,7 @@ var init_webgpu_texture_view = __esm({
247
289
  this.device = device;
248
290
  this.texture = props.texture;
249
291
  this.device.pushErrorScope("validation");
250
- this.handle = // props.handle ||
251
- this.texture.handle.createView({
292
+ this.handle = this.texture.handle.createView({
252
293
  format: this.props.format || this.texture.format,
253
294
  dimension: this.props.dimension || this.texture.dimension,
254
295
  aspect: this.props.aspect,
@@ -264,8 +305,42 @@ var init_webgpu_texture_view = __esm({
264
305
  this.handle.label = this.props.id;
265
306
  }
266
307
  destroy() {
308
+ if (this.destroyed) {
309
+ return;
310
+ }
311
+ this.destroyResource();
267
312
  this.handle = null;
268
313
  }
314
+ /**
315
+ * Internal-only hook for the cached CanvasContext/PresentationContext swapchain path.
316
+ * Rebuilds the default view when the per-frame canvas texture handle changes, without
317
+ * replacing the long-lived luma.gl wrapper object.
318
+ */
319
+ _reinitialize(texture) {
320
+ this.texture = texture;
321
+ const profiler = getCpuHotspotProfiler(this.device);
322
+ this.device.pushErrorScope("validation");
323
+ const createViewStartTime = profiler ? getTimestamp() : 0;
324
+ const handle = this.texture.handle.createView({
325
+ format: this.props.format || this.texture.format,
326
+ dimension: this.props.dimension || this.texture.dimension,
327
+ aspect: this.props.aspect,
328
+ baseMipLevel: this.props.baseMipLevel,
329
+ mipLevelCount: this.props.mipLevelCount,
330
+ baseArrayLayer: this.props.baseArrayLayer,
331
+ arrayLayerCount: this.props.arrayLayerCount
332
+ });
333
+ if (profiler) {
334
+ profiler.textureViewReinitializeCount = (profiler.textureViewReinitializeCount || 0) + 1;
335
+ profiler.textureViewReinitializeTimeMs = (profiler.textureViewReinitializeTimeMs || 0) + (getTimestamp() - createViewStartTime);
336
+ }
337
+ this.device.popErrorScope((error) => {
338
+ this.device.reportError(new Error(`TextureView constructor: ${error.message}`), this)();
339
+ this.device.debug();
340
+ });
341
+ handle.label = this.props.id;
342
+ this.handle = handle;
343
+ }
269
344
  };
270
345
  }
271
346
  });
@@ -284,9 +359,18 @@ var init_webgpu_texture = __esm({
284
359
  handle;
285
360
  sampler;
286
361
  view;
362
+ _allocatedByteLength = 0;
287
363
  constructor(device, props) {
288
364
  super(device, props, { byteAlignment: 256 });
289
365
  this.device = device;
366
+ if (props.sampler instanceof WebGPUSampler) {
367
+ this.sampler = props.sampler;
368
+ } else if (props.sampler === void 0) {
369
+ this.sampler = this.device.getDefaultSampler();
370
+ } else {
371
+ this.sampler = new WebGPUSampler(this.device, props.sampler || {});
372
+ this.attachResource(this.sampler);
373
+ }
290
374
  this.device.pushErrorScope("out-of-memory");
291
375
  this.device.pushErrorScope("validation");
292
376
  this.handle = this.props.handle || this.device.handle.createTexture({
@@ -315,7 +399,6 @@ var init_webgpu_texture = __esm({
315
399
  this.width = this.handle.width;
316
400
  this.height = this.handle.height;
317
401
  }
318
- this.sampler = props.sampler instanceof WebGPUSampler ? props.sampler : new WebGPUSampler(this.device, props.sampler || {});
319
402
  this.view = new WebGPUTextureView(this.device, {
320
403
  ...this.props,
321
404
  texture: this,
@@ -323,11 +406,26 @@ var init_webgpu_texture = __esm({
323
406
  // Note: arrayLayerCount controls the view of array textures, but does not apply to 3d texture depths
324
407
  arrayLayerCount: this.dimension !== "3d" ? this.depth : 1
325
408
  });
409
+ this.attachResource(this.view);
326
410
  this._initializeData(props.data);
411
+ this._allocatedByteLength = this.getAllocatedByteLength();
412
+ if (!this.props.handle) {
413
+ this.trackAllocatedMemory(this._allocatedByteLength, "Texture");
414
+ } else {
415
+ this.trackReferencedMemory(this._allocatedByteLength, "Texture");
416
+ }
327
417
  }
328
418
  destroy() {
329
- var _a;
330
- (_a = this.handle) == null ? void 0 : _a.destroy();
419
+ if (this.destroyed) {
420
+ return;
421
+ }
422
+ if (!this.props.handle && this.handle) {
423
+ this.trackDeallocatedMemory("Texture");
424
+ this.handle.destroy();
425
+ } else if (this.handle) {
426
+ this.trackDeallocatedReferencedMemory("Texture");
427
+ }
428
+ this.destroyResource();
331
429
  this.handle = null;
332
430
  }
333
431
  createView(props) {
@@ -363,36 +461,6 @@ var init_webgpu_texture = __esm({
363
461
  });
364
462
  return { width: options.width, height: options.height };
365
463
  }
366
- copyImageData(options_) {
367
- const { width, height, depth } = this;
368
- const options = this._normalizeCopyImageDataOptions(options_);
369
- this.device.pushErrorScope("validation");
370
- this.device.handle.queue.writeTexture(
371
- // destination: GPUImageCopyTexture
372
- {
373
- // texture subresource
374
- texture: this.handle,
375
- mipLevel: options.mipLevel,
376
- aspect: options.aspect,
377
- // origin to write to
378
- origin: [options.x, options.y, options.z]
379
- },
380
- // data
381
- options.data,
382
- // dataLayout: GPUImageDataLayout
383
- {
384
- offset: options.byteOffset,
385
- bytesPerRow: options.bytesPerRow,
386
- rowsPerImage: options.rowsPerImage
387
- },
388
- // size: GPUExtent3D - extents of the content to write
389
- [width, height, depth]
390
- );
391
- this.device.popErrorScope((error) => {
392
- this.device.reportError(new Error(`copyImageData: ${error.message}`), this)();
393
- this.device.debug();
394
- });
395
- }
396
464
  generateMipmapsWebGL() {
397
465
  import_core4.log.warn(`${this}: generateMipmaps not supported in WebGPU`)();
398
466
  }
@@ -404,13 +472,16 @@ var init_webgpu_texture = __esm({
404
472
  };
405
473
  }
406
474
  readBuffer(options = {}, buffer) {
407
- const { x = 0, y = 0, z = 0, width = this.width, height = this.height, depthOrArrayLayers = this.depth, mipLevel = 0, aspect = "all" } = options;
408
- const layout = this.computeMemoryLayout(options);
475
+ const { x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect } = this._getSupportedColorReadOptions(options);
476
+ const layout = this.computeMemoryLayout({ x, y, z, width, height, depthOrArrayLayers, mipLevel });
409
477
  const { bytesPerRow, rowsPerImage, byteLength } = layout;
410
478
  const readBuffer = buffer || this.device.createBuffer({
411
479
  byteLength,
412
480
  usage: import_core4.Buffer.COPY_DST | import_core4.Buffer.MAP_READ
413
481
  });
482
+ if (readBuffer.byteLength < byteLength) {
483
+ throw new Error(`${this} readBuffer target is too small (${readBuffer.byteLength} < ${byteLength})`);
484
+ }
414
485
  const gpuReadBuffer = readBuffer.handle;
415
486
  const gpuDevice = this.device.handle;
416
487
  this.device.pushErrorScope("validation");
@@ -454,16 +525,15 @@ var init_webgpu_texture = __esm({
454
525
  buffer.destroy();
455
526
  return data.buffer;
456
527
  }
457
- writeBuffer(buffer, options = {}) {
458
- const { x = 0, y = 0, z = 0, width = this.width, height = this.height, depthOrArrayLayers = this.depth, mipLevel = 0, aspect = "all" } = options;
459
- const layout = this.computeMemoryLayout(options);
460
- const { bytesPerRow, rowsPerImage } = layout;
528
+ writeBuffer(buffer, options_ = {}) {
529
+ const options = this._normalizeTextureWriteOptions(options_);
530
+ const { x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset, bytesPerRow, rowsPerImage } = options;
461
531
  const gpuDevice = this.device.handle;
462
532
  this.device.pushErrorScope("validation");
463
533
  const commandEncoder = gpuDevice.createCommandEncoder();
464
534
  commandEncoder.copyBufferToTexture({
465
535
  buffer: buffer.handle,
466
- offset: 0,
536
+ offset: byteOffset,
467
537
  bytesPerRow,
468
538
  rowsPerImage
469
539
  }, {
@@ -479,33 +549,88 @@ var init_webgpu_texture = __esm({
479
549
  this.device.debug();
480
550
  });
481
551
  }
482
- writeData(data, options = {}) {
552
+ writeData(data, options_ = {}) {
483
553
  const device = this.device;
484
- const { x = 0, y = 0, z = 0, width = this.width, height = this.height, depthOrArrayLayers = this.depth, mipLevel = 0, aspect = "all" } = options;
485
- const layout = import_core4.textureFormatDecoder.computeMemoryLayout({
554
+ const options = this._normalizeTextureWriteOptions(options_);
555
+ const { x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset } = options;
556
+ const source = data;
557
+ const formatInfo = this.device.getTextureFormatInfo(this.format);
558
+ const packedSourceLayout = import_core4.textureFormatDecoder.computeMemoryLayout({
486
559
  format: this.format,
487
- width: this.width,
488
- height: this.height,
489
- depth: this.depth,
490
- byteAlignment: this.byteAlignment
560
+ width,
561
+ height,
562
+ depth: depthOrArrayLayers,
563
+ byteAlignment: 1
491
564
  });
492
- const { bytesPerRow, rowsPerImage } = layout;
565
+ const bytesPerRow = options_.bytesPerRow ?? packedSourceLayout.bytesPerRow;
566
+ const rowsPerImage = options_.rowsPerImage ?? packedSourceLayout.rowsPerImage;
567
+ let copyWidth = width;
568
+ let copyHeight = height;
569
+ if (formatInfo.compressed) {
570
+ const blockWidth = formatInfo.blockWidth || 1;
571
+ const blockHeight = formatInfo.blockHeight || 1;
572
+ copyWidth = Math.ceil(width / blockWidth) * blockWidth;
573
+ copyHeight = Math.ceil(height / blockHeight) * blockHeight;
574
+ }
493
575
  this.device.pushErrorScope("validation");
494
576
  device.handle.queue.writeTexture({
495
577
  texture: this.handle,
496
578
  mipLevel,
497
579
  aspect,
498
580
  origin: { x, y, z }
499
- }, data, {
500
- offset: 0,
581
+ }, source, {
582
+ offset: byteOffset,
501
583
  bytesPerRow,
502
584
  rowsPerImage
503
- }, { width, height, depthOrArrayLayers });
585
+ }, { width: copyWidth, height: copyHeight, depthOrArrayLayers });
504
586
  this.device.popErrorScope((error) => {
505
587
  this.device.reportError(new Error(`${this} writeData: ${error.message}`), this)();
506
588
  this.device.debug();
507
589
  });
508
590
  }
591
+ /**
592
+ * Internal-only hook for the cached CanvasContext/PresentationContext swapchain path.
593
+ * Rebinds this handle-backed texture wrapper to the current per-frame canvas texture
594
+ * without allocating a new luma.gl Texture or TextureView wrapper.
595
+ */
596
+ _reinitialize(handle, props) {
597
+ const nextWidth = (props == null ? void 0 : props.width) ?? handle.width ?? this.width;
598
+ const nextHeight = (props == null ? void 0 : props.height) ?? handle.height ?? this.height;
599
+ const nextDepth = (props == null ? void 0 : props.depth) ?? this.depth;
600
+ const nextFormat = (props == null ? void 0 : props.format) ?? this.format;
601
+ const allocationMayHaveChanged = nextWidth !== this.width || nextHeight !== this.height || nextDepth !== this.depth || nextFormat !== this.format;
602
+ handle.label ||= this.id;
603
+ this.handle = handle;
604
+ this.width = nextWidth;
605
+ this.height = nextHeight;
606
+ if ((props == null ? void 0 : props.depth) !== void 0) {
607
+ this.depth = nextDepth;
608
+ }
609
+ if ((props == null ? void 0 : props.format) !== void 0) {
610
+ this.format = nextFormat;
611
+ }
612
+ this.props.handle = handle;
613
+ if ((props == null ? void 0 : props.width) !== void 0) {
614
+ this.props.width = props.width;
615
+ }
616
+ if ((props == null ? void 0 : props.height) !== void 0) {
617
+ this.props.height = props.height;
618
+ }
619
+ if ((props == null ? void 0 : props.depth) !== void 0) {
620
+ this.props.depth = props.depth;
621
+ }
622
+ if ((props == null ? void 0 : props.format) !== void 0) {
623
+ this.props.format = props.format;
624
+ }
625
+ if (allocationMayHaveChanged) {
626
+ const nextAllocation = this.getAllocatedByteLength();
627
+ if (nextAllocation !== this._allocatedByteLength) {
628
+ this._allocatedByteLength = nextAllocation;
629
+ this.trackReferencedMemory(nextAllocation, "Texture");
630
+ }
631
+ }
632
+ this.view._reinitialize(this);
633
+ }
509
634
  };
510
635
  }
511
636
  });
@@ -819,14 +944,12 @@ var init_webgpu_parameters = __esm({
819
944
  function getBindGroup(device, bindGroupLayout, shaderLayout, bindings) {
820
945
  const entries = getBindGroupEntries(bindings, shaderLayout);
821
946
  device.pushErrorScope("validation");
822
- const bindGroup = device.createBindGroup({
947
+ const bindGroup = device.handle.createBindGroup({
823
948
  layout: bindGroupLayout,
824
949
  entries
825
950
  });
826
- device.popErrorScope().then((error) => {
827
- if (error) {
828
- import_core8.log.error(`bindGroup creation: ${error.message}`, bindGroup)();
829
- }
951
+ device.popErrorScope((error) => {
952
+ import_core8.log.error(`bindGroup creation: ${error.message}`, bindGroup)();
830
953
  });
831
954
  return bindGroup;
832
955
  }
@@ -840,21 +963,21 @@ function getShaderLayoutBinding(shaderLayout, bindingName, options) {
840
963
  function getBindGroupEntries(bindings, shaderLayout) {
841
964
  const entries = [];
842
965
  for (const [bindingName, value] of Object.entries(bindings)) {
843
- let bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
844
- if (bindingLayout) {
845
- const entry = getBindGroupEntry(value, bindingLayout.location, void 0, bindingName);
966
+ const exactBindingLayout = shaderLayout.bindings.find((binding) => binding.name === bindingName);
967
+ const bindingLayout = exactBindingLayout || getShaderLayoutBinding(shaderLayout, bindingName);
968
+ const isShadowedAlias = !exactBindingLayout && bindingLayout ? bindingLayout.name in bindings : false;
969
+ if (!isShadowedAlias) {
970
+ const entry = bindingLayout ? getBindGroupEntry(value, bindingLayout.location, void 0, bindingName) : null;
846
971
  if (entry) {
847
972
  entries.push(entry);
848
973
  }
849
- }
850
- if (value instanceof import_core8.Texture) {
851
- bindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
852
- ignoreWarnings: true
853
- });
854
- if (bindingLayout) {
855
- const entry = getBindGroupEntry(value, bindingLayout.location, { sampler: true }, bindingName);
856
- if (entry) {
857
- entries.push(entry);
974
+ if (value instanceof import_core8.Texture) {
975
+ const samplerBindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
976
+ ignoreWarnings: true
977
+ });
978
+ const samplerEntry = samplerBindingLayout ? getBindGroupEntry(value, samplerBindingLayout.location, { sampler: true }, bindingName) : null;
979
+ if (samplerEntry) {
980
+ entries.push(samplerEntry);
858
981
  }
859
982
  }
860
983
  }
@@ -999,7 +1122,7 @@ var init_get_vertex_buffer_layout = __esm({
999
1122
  });
1000
1123
 
1001
1124
  // dist/adapter/resources/webgpu-render-pipeline.js
1002
- var import_core10, WebGPURenderPipeline;
1125
+ var import_core10, EMPTY_BINDINGS, WebGPURenderPipeline;
1003
1126
  var init_webgpu_render_pipeline = __esm({
1004
1127
  "dist/adapter/resources/webgpu-render-pipeline.js"() {
1005
1128
  "use strict";
@@ -1008,13 +1131,15 @@ var init_webgpu_render_pipeline = __esm({
1008
1131
  init_convert_texture_format();
1009
1132
  init_get_bind_group();
1010
1133
  init_get_vertex_buffer_layout();
1134
+ EMPTY_BINDINGS = {};
1011
1135
  WebGPURenderPipeline = class extends import_core10.RenderPipeline {
1012
1136
  device;
1013
1137
  handle;
1014
1138
  vs;
1015
1139
  fs = null;
1016
- /** For internal use to create BindGroups */
1140
+ /** Compatibility path for direct pipeline.setBindings() usage */
1017
1141
  _bindings;
1142
+ /** For internal use to create BindGroups */
1018
1143
  _bindGroupLayout = null;
1019
1144
  _bindGroup = null;
1020
1145
  get [Symbol.toStringTag]() {
@@ -1040,26 +1165,36 @@ var init_webgpu_render_pipeline = __esm({
1040
1165
  this.handle.label = this.props.id;
1041
1166
  this.vs = props.vs;
1042
1167
  this.fs = props.fs;
1043
- this._bindings = { ...this.props.bindings };
1168
+ this._bindings = props.bindings || EMPTY_BINDINGS;
1044
1169
  }
1045
1170
  destroy() {
1046
1171
  this.handle = null;
1047
1172
  }
1048
1173
  /**
1049
- * @todo Use renderpass.setBindings() ?
1050
- * @todo Do we want to expose BindGroups in the API and remove this?
1174
+ * Compatibility shim for code paths that still set bindings on the pipeline.
1175
+ * The shared-model path passes bindings per draw and does not rely on this state.
1051
1176
  */
1052
1177
  setBindings(bindings) {
1178
+ let bindingsChanged = false;
1053
1179
  for (const [name, binding] of Object.entries(bindings)) {
1054
1180
  if (this._bindings[name] !== binding) {
1055
- this._bindGroup = null;
1181
+ if (!bindingsChanged) {
1182
+ if (this._bindings === this.props.bindings || this._bindings === EMPTY_BINDINGS) {
1183
+ this._bindings = { ...this._bindings };
1184
+ }
1185
+ bindingsChanged = true;
1186
+ }
1187
+ this._bindings[name] = binding;
1056
1188
  }
1057
1189
  }
1058
- Object.assign(this._bindings, bindings);
1190
+ if (bindingsChanged) {
1191
+ this._bindGroup = null;
1192
+ }
1059
1193
  }
1060
1194
  /** @todo - should this be moved to renderpass? */
1061
1195
  draw(options) {
1062
1196
  const webgpuRenderPass = options.renderPass;
1197
+ const instanceCount = options.instanceCount && options.instanceCount > 0 ? options.instanceCount : 1;
1063
1198
  this.device.pushErrorScope("validation");
1064
1199
  webgpuRenderPass.handle.setPipeline(this.handle);
1065
1200
  this.device.popErrorScope((error) => {
@@ -1067,31 +1202,29 @@ var init_webgpu_render_pipeline = __esm({
1067
1202
  "${error.message}"`), this)();
1068
1203
  this.device.debug();
1069
1204
  });
1070
- const bindGroup = this._getBindGroup();
1205
+ const bindGroup = this._getBindGroup(options.bindings);
1071
1206
  if (bindGroup) {
1072
1207
  webgpuRenderPass.handle.setBindGroup(0, bindGroup);
1073
1208
  }
1074
1209
  options.vertexArray.bindBeforeRender(options.renderPass);
1075
1210
  if (options.indexCount) {
1076
- webgpuRenderPass.handle.drawIndexed(options.indexCount, options.instanceCount, options.firstIndex, options.baseVertex, options.firstInstance);
1211
+ webgpuRenderPass.handle.drawIndexed(options.indexCount, instanceCount, options.firstIndex || 0, options.baseVertex || 0, options.firstInstance || 0);
1077
1212
  } else {
1078
- webgpuRenderPass.handle.draw(
1079
- options.vertexCount || 0,
1080
- options.instanceCount || 1,
1081
- // If 0, nothing will be drawn
1082
- options.firstInstance
1083
- );
1213
+ webgpuRenderPass.handle.draw(options.vertexCount || 0, instanceCount, options.firstVertex || 0, options.firstInstance || 0);
1084
1214
  }
1085
1215
  options.vertexArray.unbindAfterRender(options.renderPass);
1086
1216
  return true;
1087
1217
  }
1088
1218
  /** Return a bind group created by setBindings */
1089
- _getBindGroup() {
1219
+ _getBindGroup(bindings) {
1090
1220
  if (this.shaderLayout.bindings.length === 0) {
1091
1221
  return null;
1092
1222
  }
1093
1223
  this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
1094
- this._bindGroup = this._bindGroup || getBindGroup(this.device.handle, this._bindGroupLayout, this.shaderLayout, this._bindings);
1224
+ if (bindings) {
1225
+ return getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, bindings);
1226
+ }
1227
+ this._bindGroup = this._bindGroup || getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, this._bindings);
1095
1228
  return this._bindGroup;
1096
1229
  }
1097
1230
  /**
@@ -1158,17 +1291,33 @@ var init_webgpu_framebuffer = __esm({
1158
1291
  }
1159
1292
  updateAttachments() {
1160
1293
  }
1294
+ /**
1295
+ * Internal-only hook for the cached CanvasContext/PresentationContext swapchain path.
1296
+ * Rebinds the long-lived default framebuffer wrapper to the current per-frame color view
1297
+ * and optional depth attachment without allocating a new luma.gl Framebuffer object.
1298
+ */
1299
+ _reinitialize(colorAttachment, depthStencilAttachment) {
1300
+ this.colorAttachments[0] = colorAttachment;
1301
+ this.depthStencilAttachment = depthStencilAttachment;
1302
+ this.width = colorAttachment.texture.width;
1303
+ this.height = colorAttachment.texture.height;
1304
+ this.props.width = this.width;
1305
+ this.props.height = this.height;
1306
+ this.props.colorAttachments = [colorAttachment.texture];
1307
+ this.props.depthStencilAttachment = (depthStencilAttachment == null ? void 0 : depthStencilAttachment.texture) || null;
1308
+ }
1161
1309
  };
1162
1310
  }
1163
1311
  });
1164
1312
 
1165
1313
  // dist/adapter/resources/webgpu-compute-pipeline.js
1166
- var import_core12, WebGPUComputePipeline;
1314
+ var import_core12, EMPTY_BINDINGS2, WebGPUComputePipeline;
1167
1315
  var init_webgpu_compute_pipeline = __esm({
1168
1316
  "dist/adapter/resources/webgpu-compute-pipeline.js"() {
1169
1317
  "use strict";
1170
1318
  import_core12 = require("@luma.gl/core");
1171
1319
  init_get_bind_group();
1320
+ EMPTY_BINDINGS2 = {};
1172
1321
  WebGPUComputePipeline = class extends import_core12.ComputePipeline {
1173
1322
  device;
1174
1323
  handle;
@@ -1176,7 +1325,7 @@ var init_webgpu_compute_pipeline = __esm({
1176
1325
  _bindGroupLayout = null;
1177
1326
  _bindGroup = null;
1178
1327
  /** For internal use to create BindGroups */
1179
- _bindings = {};
1328
+ _bindings;
1180
1329
  constructor(device, props) {
1181
1330
  super(device, props);
1182
1331
  this.device = device;
@@ -1190,18 +1339,33 @@ var init_webgpu_compute_pipeline = __esm({
1190
1339
  },
1191
1340
  layout: "auto"
1192
1341
  });
1342
+ this._bindings = EMPTY_BINDINGS2;
1193
1343
  }
1194
1344
  /**
1195
1345
  * @todo Use renderpass.setBindings() ?
1196
1346
  * @todo Do we want to expose BindGroups in the API and remove this?
1197
1347
  */
1198
1348
  setBindings(bindings) {
1199
- Object.assign(this._bindings, bindings);
1349
+ let bindingsChanged = false;
1350
+ for (const [name, binding] of Object.entries(bindings)) {
1351
+ if (this._bindings[name] !== binding) {
1352
+ if (!bindingsChanged) {
1353
+ if (this._bindings === EMPTY_BINDINGS2) {
1354
+ this._bindings = {};
1355
+ }
1356
+ bindingsChanged = true;
1357
+ }
1358
+ this._bindings[name] = binding;
1359
+ }
1360
+ }
1361
+ if (bindingsChanged) {
1362
+ this._bindGroup = null;
1363
+ }
1200
1364
  }
1201
1365
  /** Return a bind group created by setBindings */
1202
1366
  _getBindGroup() {
1203
1367
  this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
1204
- this._bindGroup = this._bindGroup || getBindGroup(this.device.handle, this._bindGroupLayout, this.shaderLayout, this._bindings);
1368
+ this._bindGroup = this._bindGroup || getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, this._bindings);
1205
1369
  return this._bindGroup;
1206
1370
  }
1207
1371
  };
@@ -1217,7 +1381,7 @@ var init_webgpu_vertex_array = __esm({
1217
1381
  import_env = require("@probe.gl/env");
1218
1382
  WebGPUVertexArray = class extends import_core13.VertexArray {
1219
1383
  get [Symbol.toStringTag]() {
1220
- return "WebGPUVertexArray";
1384
+ return "VertexArray";
1221
1385
  }
1222
1386
  device;
1223
1387
  /** Vertex Array is just a helper class under WebGPU */
@@ -1280,10 +1444,13 @@ var init_webgpu_canvas_context = __esm({
1280
1444
  "use strict";
1281
1445
  import_core14 = require("@luma.gl/core");
1282
1446
  init_webgpu_framebuffer();
1447
+ init_cpu_hotspot_profiler();
1283
1448
  WebGPUCanvasContext = class extends import_core14.CanvasContext {
1284
1449
  device;
1285
1450
  handle;
1451
+ colorAttachment = null;
1286
1452
  depthStencilAttachment = null;
1453
+ framebuffer = null;
1287
1454
  get [Symbol.toStringTag]() {
1288
1455
  return "WebGPUCanvasContext";
1289
1456
  }
@@ -1297,9 +1464,22 @@ var init_webgpu_canvas_context = __esm({
1297
1464
  this.handle = context;
1298
1465
  this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
1299
1466
  this._configureDevice();
1467
+ this._startObservers();
1300
1468
  }
1301
1469
  /** Destroy any textures produced while configured and remove the context configuration. */
1302
1470
  destroy() {
1471
+ if (this.framebuffer) {
1472
+ this.framebuffer.destroy();
1473
+ this.framebuffer = null;
1474
+ }
1475
+ if (this.colorAttachment) {
1476
+ this.colorAttachment.destroy();
1477
+ this.colorAttachment = null;
1478
+ }
1479
+ if (this.depthStencilAttachment) {
1480
+ this.depthStencilAttachment.destroy();
1481
+ this.depthStencilAttachment = null;
1482
+ }
1303
1483
  this.handle.unconfigure();
1304
1484
  super.destroy();
1305
1485
  }
@@ -1318,41 +1498,78 @@ var init_webgpu_canvas_context = __esm({
1318
1498
  colorSpace: this.props.colorSpace,
1319
1499
  alphaMode: this.props.alphaMode
1320
1500
  });
1501
+ this._createDepthStencilAttachment(this.device.preferredDepthFormat);
1321
1502
  }
1322
1503
  /** Update framebuffer with properly resized "swap chain" texture views */
1323
1504
  _getCurrentFramebuffer(options = {
1324
1505
  depthStencilFormat: "depth24plus"
1325
1506
  }) {
1326
- const currentColorAttachment = this._getCurrentTexture();
1327
- if (currentColorAttachment.width !== this.drawingBufferWidth || currentColorAttachment.height !== this.drawingBufferHeight) {
1328
- const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1329
- this.drawingBufferWidth = currentColorAttachment.width;
1330
- this.drawingBufferHeight = currentColorAttachment.height;
1331
- import_core14.log.log(1, `${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
1332
- }
1333
- if (options == null ? void 0 : options.depthStencilFormat) {
1334
- this._createDepthStencilAttachment(options == null ? void 0 : options.depthStencilFormat);
1335
- }
1336
- return new WebGPUFramebuffer(this.device, {
1337
- colorAttachments: [currentColorAttachment],
1338
- depthStencilAttachment: this.depthStencilAttachment
1339
- });
1507
+ var _a;
1508
+ const profiler = getCpuHotspotProfiler(this.device);
1509
+ const startTime = profiler ? getTimestamp() : 0;
1510
+ if (profiler) {
1511
+ profiler.framebufferAcquireCount = (profiler.framebufferAcquireCount || 0) + 1;
1512
+ profiler.activeDefaultFramebufferAcquireDepth = (profiler.activeDefaultFramebufferAcquireDepth || 0) + 1;
1513
+ }
1514
+ try {
1515
+ const currentColorAttachment = this._getCurrentTexture();
1516
+ if (currentColorAttachment.width !== this.drawingBufferWidth || currentColorAttachment.height !== this.drawingBufferHeight) {
1517
+ const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1518
+ this.drawingBufferWidth = currentColorAttachment.width;
1519
+ this.drawingBufferHeight = currentColorAttachment.height;
1520
+ import_core14.log.log(1, `${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
1521
+ }
1522
+ if (options == null ? void 0 : options.depthStencilFormat) {
1523
+ this._createDepthStencilAttachment(options == null ? void 0 : options.depthStencilFormat);
1524
+ }
1525
+ this.framebuffer ||= new WebGPUFramebuffer(this.device, {
1526
+ id: `${this.id}#framebuffer`,
1527
+ colorAttachments: [currentColorAttachment],
1528
+ depthStencilAttachment: null
1529
+ });
1530
+ this.framebuffer._reinitialize(currentColorAttachment.view, (options == null ? void 0 : options.depthStencilFormat) ? ((_a = this.depthStencilAttachment) == null ? void 0 : _a.view) || null : null);
1531
+ return this.framebuffer;
1532
+ } finally {
1533
+ if (profiler) {
1534
+ profiler.activeDefaultFramebufferAcquireDepth = (profiler.activeDefaultFramebufferAcquireDepth || 1) - 1;
1535
+ profiler.framebufferAcquireTimeMs = (profiler.framebufferAcquireTimeMs || 0) + (getTimestamp() - startTime);
1536
+ }
1537
+ }
1340
1538
  }
1341
1539
  // PRIMARY METHODS
1342
1540
  /** Wrap the current canvas context texture in a luma.gl texture */
1343
1541
  _getCurrentTexture() {
1542
+ const profiler = getCpuHotspotProfiler(this.device);
1543
+ const currentTextureStartTime = profiler ? getTimestamp() : 0;
1344
1544
  const handle = this.handle.getCurrentTexture();
1345
- return this.device.createTexture({
1346
- id: `${this.id}#color-texture`,
1545
+ if (profiler) {
1546
+ profiler.currentTextureAcquireCount = (profiler.currentTextureAcquireCount || 0) + 1;
1547
+ profiler.currentTextureAcquireTimeMs = (profiler.currentTextureAcquireTimeMs || 0) + (getTimestamp() - currentTextureStartTime);
1548
+ }
1549
+ if (!this.colorAttachment) {
1550
+ this.colorAttachment = this.device.createTexture({
1551
+ id: `${this.id}#color-texture`,
1552
+ handle,
1553
+ format: this.device.preferredColorFormat,
1554
+ width: handle.width,
1555
+ height: handle.height
1556
+ });
1557
+ return this.colorAttachment;
1558
+ }
1559
+ this.colorAttachment._reinitialize(handle, {
1347
1560
  handle,
1348
1561
  format: this.device.preferredColorFormat,
1349
1562
  width: handle.width,
1350
1563
  height: handle.height
1351
1564
  });
1565
+ return this.colorAttachment;
1352
1566
  }
1353
1567
  /** We build render targets on demand (i.e. not when size changes but when about to render) */
1354
1568
  _createDepthStencilAttachment(depthStencilFormat) {
1355
- if (!this.depthStencilAttachment) {
1569
+ var _a;
1570
+ const needsNewDepthStencilAttachment = !this.depthStencilAttachment || this.depthStencilAttachment.width !== this.drawingBufferWidth || this.depthStencilAttachment.height !== this.drawingBufferHeight || this.depthStencilAttachment.format !== depthStencilFormat;
1571
+ if (needsNewDepthStencilAttachment) {
1572
+ (_a = this.depthStencilAttachment) == null ? void 0 : _a.destroy();
1356
1573
  this.depthStencilAttachment = this.device.createTexture({
1357
1574
  id: `${this.id}#depth-stencil-texture`,
1358
1575
  usage: import_core14.Texture.RENDER_ATTACHMENT,
@@ -1367,17 +1584,157 @@ var init_webgpu_canvas_context = __esm({
1367
1584
  }
1368
1585
  });
1369
1586
 
1587
+ // dist/adapter/webgpu-presentation-context.js
1588
+ var import_core15, WebGPUPresentationContext;
1589
+ var init_webgpu_presentation_context = __esm({
1590
+ "dist/adapter/webgpu-presentation-context.js"() {
1591
+ "use strict";
1592
+ import_core15 = require("@luma.gl/core");
1593
+ init_webgpu_framebuffer();
1594
+ init_cpu_hotspot_profiler();
1595
+ WebGPUPresentationContext = class extends import_core15.PresentationContext {
1596
+ device;
1597
+ handle;
1598
+ colorAttachment = null;
1599
+ depthStencilAttachment = null;
1600
+ framebuffer = null;
1601
+ get [Symbol.toStringTag]() {
1602
+ return "WebGPUPresentationContext";
1603
+ }
1604
+ constructor(device, props = {}) {
1605
+ super(props);
1606
+ const contextLabel = `${this[Symbol.toStringTag]}(${this.id})`;
1607
+ const context = this.canvas.getContext("webgpu");
1608
+ if (!context) {
1609
+ throw new Error(`${contextLabel}: Failed to create WebGPU presentation context`);
1610
+ }
1611
+ this.device = device;
1612
+ this.handle = context;
1613
+ this._setAutoCreatedCanvasId(`${this.device.id}-presentation-canvas`);
1614
+ this._configureDevice();
1615
+ this._startObservers();
1616
+ }
1617
+ destroy() {
1618
+ if (this.framebuffer) {
1619
+ this.framebuffer.destroy();
1620
+ this.framebuffer = null;
1621
+ }
1622
+ if (this.colorAttachment) {
1623
+ this.colorAttachment.destroy();
1624
+ this.colorAttachment = null;
1625
+ }
1626
+ if (this.depthStencilAttachment) {
1627
+ this.depthStencilAttachment.destroy();
1628
+ this.depthStencilAttachment = null;
1629
+ }
1630
+ this.handle.unconfigure();
1631
+ super.destroy();
1632
+ }
1633
+ present() {
1634
+ this.device.submit();
1635
+ }
1636
+ _configureDevice() {
1637
+ if (this.depthStencilAttachment) {
1638
+ this.depthStencilAttachment.destroy();
1639
+ this.depthStencilAttachment = null;
1640
+ }
1641
+ this.handle.configure({
1642
+ device: this.device.handle,
1643
+ format: this.device.preferredColorFormat,
1644
+ colorSpace: this.props.colorSpace,
1645
+ alphaMode: this.props.alphaMode
1646
+ });
1647
+ this._createDepthStencilAttachment(this.device.preferredDepthFormat);
1648
+ }
1649
+ _getCurrentFramebuffer(options = {
1650
+ depthStencilFormat: "depth24plus"
1651
+ }) {
1652
+ var _a;
1653
+ const profiler = getCpuHotspotProfiler(this.device);
1654
+ const startTime = profiler ? getTimestamp() : 0;
1655
+ if (profiler) {
1656
+ profiler.framebufferAcquireCount = (profiler.framebufferAcquireCount || 0) + 1;
1657
+ }
1658
+ try {
1659
+ const currentColorAttachment = this._getCurrentTexture();
1660
+ if (currentColorAttachment.width !== this.drawingBufferWidth || currentColorAttachment.height !== this.drawingBufferHeight) {
1661
+ const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1662
+ this.drawingBufferWidth = currentColorAttachment.width;
1663
+ this.drawingBufferHeight = currentColorAttachment.height;
1664
+ import_core15.log.log(1, `${this[Symbol.toStringTag]}(${this.id}): Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
1665
+ }
1666
+ if (options == null ? void 0 : options.depthStencilFormat) {
1667
+ this._createDepthStencilAttachment(options.depthStencilFormat);
1668
+ }
1669
+ this.framebuffer ||= new WebGPUFramebuffer(this.device, {
1670
+ id: `${this.id}#framebuffer`,
1671
+ colorAttachments: [currentColorAttachment],
1672
+ depthStencilAttachment: null
1673
+ });
1674
+ this.framebuffer._reinitialize(currentColorAttachment.view, (options == null ? void 0 : options.depthStencilFormat) ? ((_a = this.depthStencilAttachment) == null ? void 0 : _a.view) || null : null);
1675
+ return this.framebuffer;
1676
+ } finally {
1677
+ if (profiler) {
1678
+ profiler.framebufferAcquireTimeMs = (profiler.framebufferAcquireTimeMs || 0) + (getTimestamp() - startTime);
1679
+ }
1680
+ }
1681
+ }
1682
+ _getCurrentTexture() {
1683
+ const profiler = getCpuHotspotProfiler(this.device);
1684
+ const currentTextureStartTime = profiler ? getTimestamp() : 0;
1685
+ const handle = this.handle.getCurrentTexture();
1686
+ if (profiler) {
1687
+ profiler.currentTextureAcquireCount = (profiler.currentTextureAcquireCount || 0) + 1;
1688
+ profiler.currentTextureAcquireTimeMs = (profiler.currentTextureAcquireTimeMs || 0) + (getTimestamp() - currentTextureStartTime);
1689
+ }
1690
+ if (!this.colorAttachment) {
1691
+ this.colorAttachment = this.device.createTexture({
1692
+ id: `${this.id}#color-texture`,
1693
+ handle,
1694
+ format: this.device.preferredColorFormat,
1695
+ width: handle.width,
1696
+ height: handle.height
1697
+ });
1698
+ return this.colorAttachment;
1699
+ }
1700
+ this.colorAttachment._reinitialize(handle, {
1701
+ handle,
1702
+ format: this.device.preferredColorFormat,
1703
+ width: handle.width,
1704
+ height: handle.height
1705
+ });
1706
+ return this.colorAttachment;
1707
+ }
1708
+ _createDepthStencilAttachment(depthStencilFormat) {
1709
+ var _a;
1710
+ const needsNewDepthStencilAttachment = !this.depthStencilAttachment || this.depthStencilAttachment.width !== this.drawingBufferWidth || this.depthStencilAttachment.height !== this.drawingBufferHeight || this.depthStencilAttachment.format !== depthStencilFormat;
1711
+ if (needsNewDepthStencilAttachment) {
1712
+ (_a = this.depthStencilAttachment) == null ? void 0 : _a.destroy();
1713
+ this.depthStencilAttachment = this.device.createTexture({
1714
+ id: `${this.id}#depth-stencil-texture`,
1715
+ usage: import_core15.Texture.RENDER_ATTACHMENT,
1716
+ format: depthStencilFormat,
1717
+ width: this.drawingBufferWidth,
1718
+ height: this.drawingBufferHeight
1719
+ });
1720
+ }
1721
+ return this.depthStencilAttachment;
1722
+ }
1723
+ };
1724
+ }
1725
+ });
1726
+
1370
1727
  // dist/adapter/resources/webgpu-command-buffer.js
1371
- var import_core15, WebGPUCommandBuffer;
1728
+ var import_core16, WebGPUCommandBuffer;
1372
1729
  var init_webgpu_command_buffer = __esm({
1373
1730
  "dist/adapter/resources/webgpu-command-buffer.js"() {
1374
1731
  "use strict";
1375
- import_core15 = require("@luma.gl/core");
1376
- WebGPUCommandBuffer = class extends import_core15.CommandBuffer {
1732
+ import_core16 = require("@luma.gl/core");
1733
+ WebGPUCommandBuffer = class extends import_core16.CommandBuffer {
1377
1734
  device;
1378
1735
  handle;
1379
1736
  constructor(commandEncoder, props) {
1380
- super(commandEncoder.device, {});
1737
+ super(commandEncoder.device, props);
1381
1738
  this.device = commandEncoder.device;
1382
1739
  this.handle = this.props.handle || commandEncoder.handle.finish({
1383
1740
  label: (props == null ? void 0 : props.id) || "unnamed-command-buffer"
@@ -1391,52 +1748,85 @@ var init_webgpu_command_buffer = __esm({
1391
1748
  function convertColor(color) {
1392
1749
  return { r: color[0], g: color[1], b: color[2], a: color[3] };
1393
1750
  }
1394
- var import_core16, WebGPURenderPass;
1751
+ var import_core17, WebGPURenderPass;
1395
1752
  var init_webgpu_render_pass = __esm({
1396
1753
  "dist/adapter/resources/webgpu-render-pass.js"() {
1397
1754
  "use strict";
1398
- import_core16 = require("@luma.gl/core");
1399
- WebGPURenderPass = class extends import_core16.RenderPass {
1755
+ import_core17 = require("@luma.gl/core");
1756
+ init_cpu_hotspot_profiler();
1757
+ WebGPURenderPass = class extends import_core17.RenderPass {
1400
1758
  device;
1401
1759
  handle;
1760
+ framebuffer;
1402
1761
  /** Active pipeline */
1403
1762
  pipeline = null;
1763
+ /** Latest bindings applied to this pass */
1764
+ bindings = {};
1404
1765
  constructor(device, props = {}) {
1405
1766
  super(device, props);
1406
1767
  this.device = device;
1407
- const framebuffer = props.framebuffer || device.getCanvasContext().getCurrentFramebuffer();
1408
- const renderPassDescriptor = this.getRenderPassDescriptor(framebuffer);
1409
- const webgpuQuerySet = props.timestampQuerySet;
1410
- if (webgpuQuerySet) {
1411
- renderPassDescriptor.occlusionQuerySet = webgpuQuerySet.handle;
1412
- }
1413
- if (device.features.has("timestamp-query")) {
1414
- const webgpuTSQuerySet = props.timestampQuerySet;
1415
- renderPassDescriptor.timestampWrites = webgpuTSQuerySet ? {
1416
- querySet: webgpuTSQuerySet.handle,
1417
- beginningOfPassWriteIndex: props.beginTimestampIndex,
1418
- endOfPassWriteIndex: props.endTimestampIndex
1419
- } : void 0;
1420
- }
1421
- if (!device.commandEncoder) {
1422
- throw new Error("commandEncoder not available");
1768
+ const { props: renderPassProps } = this;
1769
+ this.framebuffer = renderPassProps.framebuffer || device.getCanvasContext().getCurrentFramebuffer();
1770
+ const profiler = getCpuHotspotProfiler(this.device);
1771
+ if (profiler) {
1772
+ const counterName = renderPassProps.framebuffer ? "explicitFramebufferRenderPassCount" : "defaultFramebufferRenderPassCount";
1773
+ profiler[counterName] = (profiler[counterName] || 0) + 1;
1423
1774
  }
1424
- this.device.pushErrorScope("validation");
1425
- this.handle = this.props.handle || device.commandEncoder.handle.beginRenderPass(renderPassDescriptor);
1426
- this.device.popErrorScope((error) => {
1427
- this.device.reportError(new Error(`${this} creation failed:
1775
+ const startTime = profiler ? getTimestamp() : 0;
1776
+ try {
1777
+ const descriptorAssemblyStartTime = profiler ? getTimestamp() : 0;
1778
+ const renderPassDescriptor = this.getRenderPassDescriptor(this.framebuffer);
1779
+ if (renderPassProps.occlusionQuerySet) {
1780
+ renderPassDescriptor.occlusionQuerySet = renderPassProps.occlusionQuerySet.handle;
1781
+ }
1782
+ if (renderPassProps.timestampQuerySet) {
1783
+ const webgpuTSQuerySet = renderPassProps.timestampQuerySet;
1784
+ webgpuTSQuerySet == null ? void 0 : webgpuTSQuerySet._invalidateResults();
1785
+ renderPassDescriptor.timestampWrites = webgpuTSQuerySet ? {
1786
+ querySet: webgpuTSQuerySet.handle,
1787
+ beginningOfPassWriteIndex: renderPassProps.beginTimestampIndex,
1788
+ endOfPassWriteIndex: renderPassProps.endTimestampIndex
1789
+ } : void 0;
1790
+ }
1791
+ if (profiler) {
1792
+ profiler.renderPassDescriptorAssemblyCount = (profiler.renderPassDescriptorAssemblyCount || 0) + 1;
1793
+ profiler.renderPassDescriptorAssemblyTimeMs = (profiler.renderPassDescriptorAssemblyTimeMs || 0) + (getTimestamp() - descriptorAssemblyStartTime);
1794
+ }
1795
+ if (!device.commandEncoder) {
1796
+ throw new Error("commandEncoder not available");
1797
+ }
1798
+ this.device.pushErrorScope("validation");
1799
+ const beginRenderPassStartTime = profiler ? getTimestamp() : 0;
1800
+ this.handle = this.props.handle || device.commandEncoder.handle.beginRenderPass(renderPassDescriptor);
1801
+ if (profiler) {
1802
+ profiler.renderPassBeginCount = (profiler.renderPassBeginCount || 0) + 1;
1803
+ profiler.renderPassBeginTimeMs = (profiler.renderPassBeginTimeMs || 0) + (getTimestamp() - beginRenderPassStartTime);
1804
+ }
1805
+ this.device.popErrorScope((error) => {
1806
+ this.device.reportError(new Error(`${this} creation failed:
1428
1807
  "${error.message}"`), this)();
1429
- this.device.debug();
1430
- });
1431
- this.handle.label = this.props.id;
1432
- import_core16.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1433
- import_core16.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1434
- import_core16.log.groupEnd(3)();
1808
+ this.device.debug();
1809
+ });
1810
+ this.handle.label = this.props.id;
1811
+ import_core17.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1812
+ import_core17.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1813
+ import_core17.log.groupEnd(3)();
1814
+ } finally {
1815
+ if (profiler) {
1816
+ profiler.renderPassSetupCount = (profiler.renderPassSetupCount || 0) + 1;
1817
+ profiler.renderPassSetupTimeMs = (profiler.renderPassSetupTimeMs || 0) + (getTimestamp() - startTime);
1818
+ }
1819
+ }
1435
1820
  }
1436
1821
  destroy() {
1822
+ this.destroyResource();
1437
1823
  }
1438
1824
  end() {
1825
+ if (this.destroyed) {
1826
+ return;
1827
+ }
1439
1828
  this.handle.end();
1829
+ this.destroy();
1440
1830
  }
1441
1831
  setPipeline(pipeline) {
1442
1832
  this.pipeline = pipeline;
@@ -1450,9 +1840,9 @@ var init_webgpu_render_pass = __esm({
1450
1840
  }
1451
1841
  /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
1452
1842
  setBindings(bindings) {
1453
- var _a, _b;
1454
- (_a = this.pipeline) == null ? void 0 : _a.setBindings(bindings);
1455
- const bindGroup = (_b = this.pipeline) == null ? void 0 : _b._getBindGroup();
1843
+ var _a;
1844
+ this.bindings = bindings;
1845
+ const bindGroup = (_a = this.pipeline) == null ? void 0 : _a._getBindGroup(bindings);
1456
1846
  if (bindGroup) {
1457
1847
  this.handle.setBindGroup(0, bindGroup);
1458
1848
  }
@@ -1517,7 +1907,7 @@ var init_webgpu_render_pass = __esm({
1517
1907
  return {
1518
1908
  // clear values
1519
1909
  loadOp: this.props.clearColor !== false ? "clear" : "load",
1520
- clearValue: convertColor(((_a = this.props.clearColors) == null ? void 0 : _a[index]) || this.props.clearColor || import_core16.RenderPass.defaultClearColor),
1910
+ clearValue: convertColor(((_a = this.props.clearColors) == null ? void 0 : _a[index]) || this.props.clearColor || import_core17.RenderPass.defaultClearColor),
1521
1911
  storeOp: this.props.discard ? "discard" : "store",
1522
1912
  // ...colorAttachment,
1523
1913
  view: colorAttachment.handle
@@ -1552,26 +1942,28 @@ var init_webgpu_render_pass = __esm({
1552
1942
  });
1553
1943
 
1554
1944
  // dist/adapter/resources/webgpu-compute-pass.js
1555
- var import_core17, WebGPUComputePass;
1945
+ var import_core18, WebGPUComputePass;
1556
1946
  var init_webgpu_compute_pass = __esm({
1557
1947
  "dist/adapter/resources/webgpu-compute-pass.js"() {
1558
1948
  "use strict";
1559
- import_core17 = require("@luma.gl/core");
1560
- WebGPUComputePass = class extends import_core17.ComputePass {
1949
+ import_core18 = require("@luma.gl/core");
1950
+ WebGPUComputePass = class extends import_core18.ComputePass {
1561
1951
  device;
1562
1952
  handle;
1563
1953
  _webgpuPipeline = null;
1564
- constructor(device, props) {
1954
+ constructor(device, props = {}) {
1565
1955
  super(device, props);
1566
1956
  this.device = device;
1957
+ const { props: computePassProps } = this;
1567
1958
  let timestampWrites;
1568
- if (device.features.has("timestamp-query")) {
1569
- const webgpuQuerySet = props.timestampQuerySet;
1959
+ if (computePassProps.timestampQuerySet) {
1960
+ const webgpuQuerySet = computePassProps.timestampQuerySet;
1570
1961
  if (webgpuQuerySet) {
1962
+ webgpuQuerySet._invalidateResults();
1571
1963
  timestampWrites = {
1572
1964
  querySet: webgpuQuerySet.handle,
1573
- beginningOfPassWriteIndex: props.beginTimestampIndex,
1574
- endOfPassWriteIndex: props.endTimestampIndex
1965
+ beginningOfPassWriteIndex: computePassProps.beginTimestampIndex,
1966
+ endOfPassWriteIndex: computePassProps.endTimestampIndex
1575
1967
  };
1576
1968
  }
1577
1969
  }
@@ -1582,9 +1974,14 @@ var init_webgpu_compute_pass = __esm({
1582
1974
  }
1583
1975
  /** @note no WebGPU destroy method, just gc */
1584
1976
  destroy() {
1977
+ this.destroyResource();
1585
1978
  }
1586
1979
  end() {
1980
+ if (this.destroyed) {
1981
+ return;
1982
+ }
1587
1983
  this.handle.end();
1984
+ this.destroy();
1588
1985
  }
1589
1986
  setPipeline(pipeline) {
1590
1987
  const wgpuPipeline = pipeline;
@@ -1634,15 +2031,15 @@ var init_webgpu_compute_pass = __esm({
1634
2031
  });
1635
2032
 
1636
2033
  // dist/adapter/resources/webgpu-command-encoder.js
1637
- var import_core18, WebGPUCommandEncoder;
2034
+ var import_core19, WebGPUCommandEncoder;
1638
2035
  var init_webgpu_command_encoder = __esm({
1639
2036
  "dist/adapter/resources/webgpu-command-encoder.js"() {
1640
2037
  "use strict";
1641
- import_core18 = require("@luma.gl/core");
2038
+ import_core19 = require("@luma.gl/core");
1642
2039
  init_webgpu_command_buffer();
1643
2040
  init_webgpu_render_pass();
1644
2041
  init_webgpu_compute_pass();
1645
- WebGPUCommandEncoder = class extends import_core18.CommandEncoder {
2042
+ WebGPUCommandEncoder = class extends import_core19.CommandEncoder {
1646
2043
  device;
1647
2044
  handle;
1648
2045
  constructor(device, props = {}) {
@@ -1656,6 +2053,7 @@ var init_webgpu_command_encoder = __esm({
1656
2053
  this.handle.label = this.props.id;
1657
2054
  }
1658
2055
  destroy() {
2056
+ this.destroyResource();
1659
2057
  }
1660
2058
  finish(props) {
1661
2059
  this.device.pushErrorScope("validation");
@@ -1667,17 +2065,18 @@ var init_webgpu_command_encoder = __esm({
1667
2065
  this.device.reportError(new Error(message), this)();
1668
2066
  this.device.debug();
1669
2067
  });
2068
+ this.destroy();
1670
2069
  return commandBuffer;
1671
2070
  }
1672
2071
  /**
1673
2072
  * Allows a render pass to begin against a canvas context
1674
2073
  * @todo need to support a "Framebuffer" equivalent (aka preconfigured RenderPassDescriptors?).
1675
2074
  */
1676
- beginRenderPass(props) {
1677
- return new WebGPURenderPass(this.device, props);
2075
+ beginRenderPass(props = {}) {
2076
+ return new WebGPURenderPass(this.device, this._applyTimeProfilingToPassProps(props));
1678
2077
  }
1679
- beginComputePass(props) {
1680
- return new WebGPUComputePass(this.device, props);
2078
+ beginComputePass(props = {}) {
2079
+ return new WebGPUComputePass(this.device, this._applyTimeProfilingToPassProps(props));
1681
2080
  }
1682
2081
  // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
1683
2082
  // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
@@ -1725,19 +2124,40 @@ var init_webgpu_command_encoder = __esm({
1725
2124
  const webgpuBuffer = destination;
1726
2125
  this.handle.resolveQuerySet(webgpuQuerySet.handle, (options == null ? void 0 : options.firstQuery) || 0, (options == null ? void 0 : options.queryCount) || querySet.props.count - ((options == null ? void 0 : options.firstQuery) || 0), webgpuBuffer.handle, (options == null ? void 0 : options.destinationOffset) || 0);
1727
2126
  }
2127
+ writeTimestamp(querySet, queryIndex) {
2128
+ querySet._invalidateResults();
2129
+ const writeTimestamp = this.handle.writeTimestamp;
2130
+ if (writeTimestamp) {
2131
+ writeTimestamp.call(this.handle, querySet.handle, queryIndex);
2132
+ return;
2133
+ }
2134
+ const computePass = this.handle.beginComputePass({
2135
+ timestampWrites: {
2136
+ querySet: querySet.handle,
2137
+ beginningOfPassWriteIndex: queryIndex
2138
+ }
2139
+ });
2140
+ computePass.end();
2141
+ }
1728
2142
  };
1729
2143
  }
1730
2144
  });
1731
2145
 
1732
2146
  // dist/adapter/resources/webgpu-query-set.js
1733
- var import_core19, WebGPUQuerySet;
2147
+ var import_core20, WebGPUQuerySet;
1734
2148
  var init_webgpu_query_set = __esm({
1735
2149
  "dist/adapter/resources/webgpu-query-set.js"() {
1736
2150
  "use strict";
1737
- import_core19 = require("@luma.gl/core");
1738
- WebGPUQuerySet = class extends import_core19.QuerySet {
2151
+ import_core20 = require("@luma.gl/core");
2152
+ init_cpu_hotspot_profiler();
2153
+ WebGPUQuerySet = class extends import_core20.QuerySet {
1739
2154
  device;
1740
2155
  handle;
2156
+ _resolveBuffer = null;
2157
+ _readBuffer = null;
2158
+ _cachedResults = null;
2159
+ _readResultsPromise = null;
2160
+ _resultsPendingResolution = false;
1741
2161
  constructor(device, props) {
1742
2162
  super(device, props);
1743
2163
  this.device = device;
@@ -1749,20 +2169,145 @@ var init_webgpu_query_set = __esm({
1749
2169
  }
1750
2170
  destroy() {
1751
2171
  var _a;
1752
- (_a = this.handle) == null ? void 0 : _a.destroy();
1753
- this.handle = null;
2172
+ if (!this.destroyed) {
2173
+ (_a = this.handle) == null ? void 0 : _a.destroy();
2174
+ this.destroyResource();
2175
+ this.handle = null;
2176
+ }
2177
+ }
2178
+ isResultAvailable(queryIndex) {
2179
+ if (!this._cachedResults) {
2180
+ return false;
2181
+ }
2182
+ return queryIndex === void 0 ? true : queryIndex >= 0 && queryIndex < this._cachedResults.length;
2183
+ }
2184
+ async readResults(options) {
2185
+ const firstQuery = (options == null ? void 0 : options.firstQuery) || 0;
2186
+ const queryCount = (options == null ? void 0 : options.queryCount) || this.props.count - firstQuery;
2187
+ if (firstQuery < 0 || queryCount < 0 || firstQuery + queryCount > this.props.count) {
2188
+ throw new Error("Query read range is out of bounds");
2189
+ }
2190
+ let needsFreshResults = true;
2191
+ while (needsFreshResults) {
2192
+ if (!this._readResultsPromise) {
2193
+ this._readResultsPromise = this._readAllResults();
2194
+ }
2195
+ const readResultsPromise = this._readResultsPromise;
2196
+ const results = await readResultsPromise;
2197
+ needsFreshResults = this._resultsPendingResolution;
2198
+ if (!needsFreshResults) {
2199
+ return results.slice(firstQuery, firstQuery + queryCount);
2200
+ }
2201
+ }
2202
+ throw new Error("Query read unexpectedly failed to resolve");
2203
+ }
2204
+ async readTimestampDuration(beginIndex, endIndex) {
2205
+ if (this.props.type !== "timestamp") {
2206
+ throw new Error("Timestamp durations require a timestamp QuerySet");
2207
+ }
2208
+ if (beginIndex < 0 || endIndex <= beginIndex || endIndex >= this.props.count) {
2209
+ throw new Error("Timestamp duration range is out of bounds");
2210
+ }
2211
+ const results = await this.readResults({
2212
+ firstQuery: beginIndex,
2213
+ queryCount: endIndex - beginIndex + 1
2214
+ });
2215
+ return Number(results[results.length - 1] - results[0]) / 1e6;
2216
+ }
2217
+ /** Marks any cached query results as stale after new writes have been encoded. */
2218
+ _invalidateResults() {
2219
+ this._cachedResults = null;
2220
+ this._resultsPendingResolution = true;
2221
+ }
2222
+ async _readAllResults() {
2223
+ this._ensureBuffers();
2224
+ try {
2225
+ if (this._resultsPendingResolution) {
2226
+ const commandEncoder = this.device.createCommandEncoder({
2227
+ id: `${this.id}-read-results`
2228
+ });
2229
+ commandEncoder.resolveQuerySet(this, this._resolveBuffer);
2230
+ commandEncoder.copyBufferToBuffer({
2231
+ sourceBuffer: this._resolveBuffer,
2232
+ destinationBuffer: this._readBuffer,
2233
+ size: this._resolveBuffer.byteLength
2234
+ });
2235
+ const commandBuffer = commandEncoder.finish({
2236
+ id: `${this.id}-read-results-command-buffer`
2237
+ });
2238
+ const previousSubmitReason = getCpuHotspotSubmitReason(this.device) || void 0;
2239
+ setCpuHotspotSubmitReason(this.device, "query-readback");
2240
+ try {
2241
+ this.device.submit(commandBuffer);
2242
+ } finally {
2243
+ setCpuHotspotSubmitReason(this.device, previousSubmitReason);
2244
+ }
2245
+ }
2246
+ const data = await this._readBuffer.readAsync(0, this._readBuffer.byteLength);
2247
+ const resultView = new BigUint64Array(data.buffer, data.byteOffset, this.props.count);
2248
+ this._cachedResults = Array.from(resultView, (value) => value);
2249
+ this._resultsPendingResolution = false;
2250
+ return this._cachedResults;
2251
+ } finally {
2252
+ this._readResultsPromise = null;
2253
+ }
2254
+ }
2255
+ _ensureBuffers() {
2256
+ if (this._resolveBuffer && this._readBuffer) {
2257
+ return;
2258
+ }
2259
+ const byteLength = this.props.count * 8;
2260
+ this._resolveBuffer = this.device.createBuffer({
2261
+ id: `${this.id}-resolve-buffer`,
2262
+ usage: import_core20.Buffer.QUERY_RESOLVE | import_core20.Buffer.COPY_SRC,
2263
+ byteLength
2264
+ });
2265
+ this.attachResource(this._resolveBuffer);
2266
+ this._readBuffer = this.device.createBuffer({
2267
+ id: `${this.id}-read-buffer`,
2268
+ usage: import_core20.Buffer.COPY_DST | import_core20.Buffer.MAP_READ,
2269
+ byteLength
2270
+ });
2271
+ this.attachResource(this._readBuffer);
2272
+ }
2273
+ _encodeResolveToReadBuffer(commandEncoder, options) {
2274
+ if (!this._resultsPendingResolution) {
2275
+ return false;
2276
+ }
2277
+ if (this._readResultsPromise) {
2278
+ return false;
2279
+ }
2280
+ this._ensureBuffers();
2281
+ const firstQuery = (options == null ? void 0 : options.firstQuery) || 0;
2282
+ const queryCount = (options == null ? void 0 : options.queryCount) || this.props.count - firstQuery;
2283
+ const byteLength = queryCount * BigUint64Array.BYTES_PER_ELEMENT;
2284
+ const byteOffset = firstQuery * BigUint64Array.BYTES_PER_ELEMENT;
2285
+ commandEncoder.resolveQuerySet(this, this._resolveBuffer, {
2286
+ firstQuery,
2287
+ queryCount,
2288
+ destinationOffset: byteOffset
2289
+ });
2290
+ commandEncoder.copyBufferToBuffer({
2291
+ sourceBuffer: this._resolveBuffer,
2292
+ sourceOffset: byteOffset,
2293
+ destinationBuffer: this._readBuffer,
2294
+ destinationOffset: byteOffset,
2295
+ size: byteLength
2296
+ });
2297
+ this._resultsPendingResolution = false;
2298
+ return true;
1754
2299
  }
1755
2300
  };
1756
2301
  }
1757
2302
  });
1758
2303
 
1759
2304
  // dist/adapter/resources/webgpu-pipeline-layout.js
1760
- var import_core20, WebGPUPipelineLayout, isStorageTextureBindingLayout;
2305
+ var import_core21, WebGPUPipelineLayout, isStorageTextureBindingLayout;
1761
2306
  var init_webgpu_pipeline_layout = __esm({
1762
2307
  "dist/adapter/resources/webgpu-pipeline-layout.js"() {
1763
2308
  "use strict";
1764
- import_core20 = require("@luma.gl/core");
1765
- WebGPUPipelineLayout = class extends import_core20.PipelineLayout {
2309
+ import_core21 = require("@luma.gl/core");
2310
+ WebGPUPipelineLayout = class extends import_core21.PipelineLayout {
1766
2311
  device;
1767
2312
  handle;
1768
2313
  constructor(device, props) {
@@ -1839,7 +2384,7 @@ var init_webgpu_pipeline_layout = __esm({
1839
2384
  break;
1840
2385
  }
1841
2386
  default: {
1842
- import_core20.log.warn("unhandled binding type when creating pipeline descriptor")();
2387
+ import_core21.log.warn("unhandled binding type when creating pipeline descriptor")();
1843
2388
  }
1844
2389
  }
1845
2390
  const VISIBILITY_ALL = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE;
@@ -1859,12 +2404,12 @@ var init_webgpu_pipeline_layout = __esm({
1859
2404
  });
1860
2405
 
1861
2406
  // dist/adapter/resources/webgpu-fence.js
1862
- var import_core21, WebGPUFence;
2407
+ var import_core22, WebGPUFence;
1863
2408
  var init_webgpu_fence = __esm({
1864
2409
  "dist/adapter/resources/webgpu-fence.js"() {
1865
2410
  "use strict";
1866
- import_core21 = require("@luma.gl/core");
1867
- WebGPUFence = class extends import_core21.Fence {
2411
+ import_core22 = require("@luma.gl/core");
2412
+ WebGPUFence = class extends import_core22.Fence {
1868
2413
  device;
1869
2414
  handle = null;
1870
2415
  signaled;
@@ -1893,7 +2438,7 @@ function getShaderLayoutFromWGSL(source) {
1893
2438
  try {
1894
2439
  parsedWGSL = parseWGSL(source);
1895
2440
  } catch (error) {
1896
- import_core22.log.error(error.message)();
2441
+ import_core23.log.error(error.message)();
1897
2442
  return shaderLayout;
1898
2443
  }
1899
2444
  for (const uniform of parsedWGSL.uniforms) {
@@ -1987,25 +2532,508 @@ function getTextureBindingFromReflect(v, opts) {
1987
2532
  }
1988
2533
  return { viewDimension, sampleType, multisampled };
1989
2534
  }
1990
- var import_core22, import_wgsl_reflect;
2535
+ var import_core23, import_wgsl_reflect;
1991
2536
  var init_get_shader_layout_wgsl = __esm({
1992
2537
  "dist/wgsl/get-shader-layout-wgsl.js"() {
1993
2538
  "use strict";
1994
- import_core22 = require("@luma.gl/core");
2539
+ import_core23 = require("@luma.gl/core");
1995
2540
  import_wgsl_reflect = require("wgsl_reflect");
1996
2541
  }
1997
2542
  });
1998
2543
 
2544
+ // dist/adapter/helpers/generate-mipmaps-webgpu.js
2545
+ function generateMipmapsWebGPU(device, texture) {
2546
+ if (texture.mipLevels <= 1) {
2547
+ return;
2548
+ }
2549
+ if (texture.dimension === "3d") {
2550
+ generateMipmaps3D(device, texture);
2551
+ return;
2552
+ }
2553
+ if (RENDER_DIMENSIONS.includes(texture.dimension)) {
2554
+ generateMipmapsRender(device, texture);
2555
+ return;
2556
+ }
2557
+ throw new Error(`Cannot generate mipmaps for texture dimension "${texture.dimension}" with WebGPU.`);
2558
+ }
2559
+ function generateMipmapsRender(device, texture) {
2560
+ validateFormatCapabilities(device, texture, ["render", "filter"], "render");
2561
+ const colorAttachmentFormat = getColorAttachmentFormat(texture.format, "render", texture.dimension);
2562
+ const viewDimension = texture.dimension;
2563
+ const shaderSource = getRenderMipmapWGSL(viewDimension);
2564
+ const sampler = device.createSampler({ minFilter: "linear", magFilter: "linear" });
2565
+ const uniformsBuffer = device.createBuffer({
2566
+ byteLength: 16,
2567
+ usage: import_core24.Buffer.UNIFORM | import_core24.Buffer.COPY_DST
2568
+ });
2569
+ const uniformValues = new Uint32Array(1);
2570
+ const sourceTextureLayout = {
2571
+ type: "texture",
2572
+ name: "sourceTexture",
2573
+ group: 0,
2574
+ location: 1,
2575
+ viewDimension,
2576
+ sampleType: "float"
2577
+ };
2578
+ const uniformsLayout = {
2579
+ type: "uniform",
2580
+ name: "uniforms",
2581
+ group: 0,
2582
+ location: 2
2583
+ };
2584
+ const renderShaderLayout = {
2585
+ attributes: [],
2586
+ bindings: [RENDER_SOURCE_SAMPLER_LAYOUT, sourceTextureLayout, uniformsLayout]
2587
+ };
2588
+ const vertexShader = device.createShader({
2589
+ id: "mipmap-generation-render-vs",
2590
+ source: shaderSource,
2591
+ language: "wgsl",
2592
+ stage: "vertex"
2593
+ });
2594
+ const fragmentShader = device.createShader({
2595
+ id: "mipmap-generation-render-fs",
2596
+ source: shaderSource,
2597
+ language: "wgsl",
2598
+ stage: "fragment"
2599
+ });
2600
+ const renderPipeline = device.createRenderPipeline({
2601
+ id: `mipmap-generation-render:${texture.dimension}:${texture.format}`,
2602
+ vs: vertexShader,
2603
+ fs: fragmentShader,
2604
+ shaderLayout: renderShaderLayout,
2605
+ colorAttachmentFormats: [colorAttachmentFormat],
2606
+ topology: "triangle-list"
2607
+ });
2608
+ let sourceWidth = texture.width;
2609
+ let sourceHeight = texture.height;
2610
+ const layerCount = texture.dimension === "2d" ? 1 : texture.depth;
2611
+ function renderMipmapLayer(sourceView, baseMipLevel, baseArrayLayer, destinationWidth, destinationHeight) {
2612
+ uniformValues[0] = baseArrayLayer;
2613
+ uniformsBuffer.write(uniformValues);
2614
+ const destinationView = texture.createView({
2615
+ dimension: "2d",
2616
+ baseMipLevel,
2617
+ mipLevelCount: 1,
2618
+ baseArrayLayer,
2619
+ arrayLayerCount: 1
2620
+ });
2621
+ const framebuffer = device.createFramebuffer({
2622
+ colorAttachments: [destinationView]
2623
+ });
2624
+ const renderPass = device.beginRenderPass({
2625
+ id: `mipmap-generation:${texture.format}:${baseMipLevel}:${baseArrayLayer}`,
2626
+ framebuffer
2627
+ });
2628
+ try {
2629
+ renderPass.setPipeline(renderPipeline);
2630
+ renderPass.setBindings({
2631
+ sourceSampler: sampler,
2632
+ sourceTexture: sourceView,
2633
+ uniforms: uniformsBuffer
2634
+ });
2635
+ renderPass.setParameters({
2636
+ viewport: [0, 0, destinationWidth, destinationHeight, 0, 1],
2637
+ scissorRect: [0, 0, destinationWidth, destinationHeight]
2638
+ });
2639
+ renderPass.draw({ vertexCount: 3 });
2640
+ renderPass.end();
2641
+ device.submit();
2642
+ } finally {
2643
+ destinationView.destroy();
2644
+ framebuffer.destroy();
2645
+ }
2646
+ }
2647
+ try {
2648
+ for (let baseMipLevel = 1; baseMipLevel < texture.mipLevels; ++baseMipLevel) {
2649
+ validateFormatCapabilities(device, texture, ["render", "filter"], "render");
2650
+ const sourceMipLevel = baseMipLevel - 1;
2651
+ const destinationWidth = Math.max(1, sourceWidth >> 1);
2652
+ const destinationHeight = Math.max(1, sourceHeight >> 1);
2653
+ const sourceView = texture.createView({
2654
+ dimension: viewDimension,
2655
+ baseMipLevel: sourceMipLevel,
2656
+ mipLevelCount: 1,
2657
+ baseArrayLayer: 0,
2658
+ arrayLayerCount: texture.depth
2659
+ });
2660
+ try {
2661
+ for (let baseArrayLayer = 0; baseArrayLayer < layerCount; ++baseArrayLayer) {
2662
+ renderMipmapLayer(sourceView, baseMipLevel, baseArrayLayer, destinationWidth, destinationHeight);
2663
+ }
2664
+ } finally {
2665
+ sourceView.destroy();
2666
+ }
2667
+ sourceWidth = destinationWidth;
2668
+ sourceHeight = destinationHeight;
2669
+ }
2670
+ } finally {
2671
+ renderPipeline.destroy();
2672
+ vertexShader.destroy();
2673
+ fragmentShader.destroy();
2674
+ sampler.destroy();
2675
+ uniformsBuffer.destroy();
2676
+ }
2677
+ }
2678
+ function getColorAttachmentFormat(format, path, dimension) {
2679
+ if (import_core24.textureFormatDecoder.isColor(format)) {
2680
+ return format;
2681
+ }
2682
+ throw new Error(`Cannot run ${path} mipmap generation for ${dimension} texture with format "${format}". Only color textures can be used for this operation. Required capabilities: color. Actual capabilities: color=false.`);
2683
+ }
2684
+ function generateMipmaps3D(device, texture) {
2685
+ validateFormatCapabilities(device, texture, ["filter", "store"], "compute");
2686
+ const format = getColorAttachmentFormat(texture.format, "compute", texture.dimension);
2687
+ const shaderSource = get3DComputeMipmapWGSL(format);
2688
+ const destinationTextureLayout = {
2689
+ type: "storage",
2690
+ name: "destinationTexture",
2691
+ group: 0,
2692
+ location: 1,
2693
+ format,
2694
+ viewDimension: "3d",
2695
+ access: "write-only"
2696
+ };
2697
+ const computeShaderLayout = {
2698
+ bindings: [COMPUTE_SOURCE_TEXTURE_LAYOUT, destinationTextureLayout, COMPUTE_UNIFORMS_LAYOUT]
2699
+ };
2700
+ const computeShader = device.createShader({
2701
+ id: "mipmap-generation-compute",
2702
+ source: shaderSource,
2703
+ language: "wgsl",
2704
+ stage: "compute"
2705
+ });
2706
+ const computePipeline = device.createComputePipeline({
2707
+ id: `mipmap-generation-compute:${texture.format}`,
2708
+ shader: computeShader,
2709
+ shaderLayout: computeShaderLayout
2710
+ });
2711
+ const uniformsBuffer = device.createBuffer({
2712
+ byteLength: 32,
2713
+ usage: import_core24.Buffer.UNIFORM | import_core24.Buffer.COPY_DST
2714
+ });
2715
+ const uniformValues = new Uint32Array(8);
2716
+ let sourceWidth = texture.width;
2717
+ let sourceHeight = texture.height;
2718
+ let sourceDepth = texture.depth;
2719
+ try {
2720
+ for (let destinationMipLevel = 1; destinationMipLevel < texture.mipLevels; ++destinationMipLevel) {
2721
+ validateFormatCapabilities(device, texture, ["filter", "store"], "compute");
2722
+ const destinationWidth = Math.max(1, sourceWidth >> 1);
2723
+ const destinationHeight = Math.max(1, sourceHeight >> 1);
2724
+ const destinationDepth = Math.max(1, sourceDepth >> 1);
2725
+ uniformValues[0] = sourceWidth;
2726
+ uniformValues[1] = sourceHeight;
2727
+ uniformValues[2] = sourceDepth;
2728
+ uniformValues[3] = destinationWidth;
2729
+ uniformValues[4] = destinationHeight;
2730
+ uniformValues[5] = destinationDepth;
2731
+ uniformValues[6] = 0;
2732
+ uniformsBuffer.write(uniformValues);
2733
+ const sourceView = texture.createView({
2734
+ dimension: "3d",
2735
+ baseMipLevel: destinationMipLevel - 1,
2736
+ mipLevelCount: 1,
2737
+ baseArrayLayer: 0,
2738
+ arrayLayerCount: 1
2739
+ });
2740
+ const destinationView = texture.createView({
2741
+ dimension: "3d",
2742
+ baseMipLevel: destinationMipLevel,
2743
+ mipLevelCount: 1,
2744
+ baseArrayLayer: 0,
2745
+ arrayLayerCount: 1
2746
+ });
2747
+ computePipeline.setBindings({
2748
+ sourceTexture: sourceView,
2749
+ destinationTexture: destinationView,
2750
+ uniforms: uniformsBuffer
2751
+ });
2752
+ try {
2753
+ const workgroupsX = Math.ceil(destinationWidth / WORKGROUP_SIZE.x);
2754
+ const workgroupsY = Math.ceil(destinationHeight / WORKGROUP_SIZE.y);
2755
+ const workgroupsZ = Math.ceil(destinationDepth / WORKGROUP_SIZE.z);
2756
+ const computePass = device.beginComputePass({});
2757
+ computePass.setPipeline(computePipeline);
2758
+ computePass.dispatch(workgroupsX, workgroupsY, workgroupsZ);
2759
+ computePass.end();
2760
+ device.submit();
2761
+ } finally {
2762
+ sourceView.destroy();
2763
+ destinationView.destroy();
2764
+ }
2765
+ sourceWidth = destinationWidth;
2766
+ sourceHeight = destinationHeight;
2767
+ sourceDepth = destinationDepth;
2768
+ }
2769
+ } finally {
2770
+ computePipeline.destroy();
2771
+ computeShader.destroy();
2772
+ uniformsBuffer.destroy();
2773
+ }
2774
+ }
2775
+ function validateFormatCapabilities(device, texture, requiredCapabilities, path) {
2776
+ const { format, dimension } = texture;
2777
+ const capabilities = device.getTextureFormatCapabilities(format);
2778
+ const missingCapabilities = requiredCapabilities.filter((capability) => !capabilities[capability]);
2779
+ if (missingCapabilities.length > 0) {
2780
+ const required = requiredCapabilities.join(" + ");
2781
+ const actual = requiredCapabilities.map((capability) => `${capability}=${capabilities[capability]}`).join(", ");
2782
+ throw new Error(`Cannot run ${path} mipmap generation for ${dimension} texture with format "${format}". Required capabilities: ${required}. Actual capabilities: ${actual}.`);
2783
+ }
2784
+ }
2785
+ function getSourceTextureType(dimension) {
2786
+ switch (dimension) {
2787
+ case "2d":
2788
+ return "texture_2d<f32>";
2789
+ case "2d-array":
2790
+ return "texture_2d_array<f32>";
2791
+ case "cube":
2792
+ return "texture_cube<f32>";
2793
+ case "cube-array":
2794
+ return "texture_cube_array<f32>";
2795
+ default:
2796
+ throw new Error(`Unsupported render dimension "${dimension}" for mipmap generation.`);
2797
+ }
2798
+ }
2799
+ function getRenderMipmapWGSL(dimension) {
2800
+ const sourceSnippet = getRenderMipmapSampleSnippet(dimension);
2801
+ return `
2802
+ struct MipmapUniforms {
2803
+ sourceLayer: u32,
2804
+ };
2805
+
2806
+ fn _touchUniform(uniforms: MipmapUniforms) {
2807
+ let unusedSourceLayer = uniforms.sourceLayer;
2808
+ }
2809
+
2810
+ const faceMat = array(
2811
+ mat3x3f(
2812
+ 0.0, 0.0, -2.0,
2813
+ 0.0, -2.0, 0.0,
2814
+ 1.0, 1.0, 1.0
2815
+ ), // pos-x
2816
+ mat3x3f(
2817
+ 0.0, 0.0, 2.0,
2818
+ 0.0, -2.0, 0.0,
2819
+ -1.0, 1.0, -1.0
2820
+ ), // neg-x
2821
+ mat3x3f(
2822
+ 2.0, 0.0, 0.0,
2823
+ 0.0, 0.0, 2.0,
2824
+ -1.0, 1.0, -1.0
2825
+ ), // pos-y
2826
+ mat3x3f(
2827
+ 2.0, 0.0, 0.0,
2828
+ 0.0, 0.0, -2.0,
2829
+ -1.0, -1.0, 1.0
2830
+ ), // neg-y
2831
+ mat3x3f(
2832
+ 2.0, 0.0, 0.0,
2833
+ 0.0, -2.0, 0.0,
2834
+ -1.0, 1.0, 1.0
2835
+ ), // pos-z
2836
+ mat3x3f(
2837
+ -2.0, 0.0, 0.0,
2838
+ 0.0, -2.0, 0.0,
2839
+ 1.0, 1.0, -1.0
2840
+ ) // neg-z
2841
+ );
2842
+
2843
+ struct FragmentInputs {
2844
+ @builtin(position) position: vec4f,
2845
+ @location(0) texcoord: vec2f
2846
+ };
2847
+
2848
+ struct VertexOutput {
2849
+ @builtin(position) position: vec4f,
2850
+ @location(0) texcoord: vec2f
2851
+ };
2852
+
2853
+ @group(0) @binding(0) var sourceSampler: sampler;
2854
+ @group(0) @binding(1) var sourceTexture: ${getSourceTextureType(dimension)};
2855
+ @group(0) @binding(2) var<uniform> uniforms: MipmapUniforms;
2856
+
2857
+ @vertex
2858
+ fn vertexMain(
2859
+ @builtin(vertex_index) vertexIndex: u32
2860
+ ) -> VertexOutput {
2861
+ const positions = array(
2862
+ vec2f(-1.0, -1.0),
2863
+ vec2f(-1.0, 3.0),
2864
+ vec2f( 3.0, -1.0)
2865
+ );
2866
+
2867
+ let xy = positions[vertexIndex];
2868
+ return VertexOutput(
2869
+ vec4f(xy, 0.0, 1.0),
2870
+ xy * vec2f(0.5, -0.5) + vec2f(0.5)
2871
+ );
2872
+ }
2873
+
2874
+ @fragment
2875
+ fn fragmentMain(fsInput: VertexOutput) -> @location(0) vec4f {
2876
+ _touchUniform(uniforms);
2877
+ return ${sourceSnippet};
2878
+ }
2879
+ `;
2880
+ }
2881
+ function getRenderMipmapSampleSnippet(dimension) {
2882
+ const layer = "uniforms.sourceLayer";
2883
+ switch (dimension) {
2884
+ case "2d":
2885
+ return "textureSampleLevel(sourceTexture, sourceSampler, fsInput.texcoord, 0.0)";
2886
+ case "2d-array":
2887
+ return `textureSampleLevel(sourceTexture, sourceSampler, fsInput.texcoord, i32(${layer}), 0.0)`;
2888
+ case "cube":
2889
+ return `textureSampleLevel(sourceTexture, sourceSampler, faceMat[i32(${layer})] * vec3f(fract(fsInput.texcoord), 1.0), 0.0)`;
2890
+ case "cube-array":
2891
+ return `textureSampleLevel(sourceTexture, sourceSampler, faceMat[i32(${layer} % 6u)] * vec3f(fract(fsInput.texcoord), 1.0), i32(${layer} / 6u), 0.0)`;
2892
+ default:
2893
+ throw new Error(`Unsupported render dimension "${dimension}" for mipmap generation.`);
2894
+ }
2895
+ }
2896
+ function get3DComputeMipmapWGSL(format) {
2897
+ return `
2898
+ struct MipmapUniforms {
2899
+ sourceWidth: u32,
2900
+ sourceHeight: u32,
2901
+ sourceDepth: u32,
2902
+ destinationWidth: u32,
2903
+ destinationHeight: u32,
2904
+ destinationDepth: u32,
2905
+ padding: u32,
2906
+ };
2907
+
2908
+ @group(0) @binding(0) var sourceTexture: texture_3d<f32>;
2909
+ @group(0) @binding(1) var destinationTexture: texture_storage_3d<${format}, write>;
2910
+ @group(0) @binding(2) var<uniform> uniforms: MipmapUniforms;
2911
+
2912
+ @compute @workgroup_size(${WORKGROUP_SIZE.x}, ${WORKGROUP_SIZE.y}, ${WORKGROUP_SIZE.z})
2913
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
2914
+ if (
2915
+ id.x >= uniforms.destinationWidth ||
2916
+ id.y >= uniforms.destinationHeight ||
2917
+ id.z >= uniforms.destinationDepth
2918
+ ) {
2919
+ return;
2920
+ }
2921
+
2922
+ let sourceBase = id * 2u;
2923
+ let sourceX0 = min(sourceBase.x, uniforms.sourceWidth - 1u);
2924
+ let sourceY0 = min(sourceBase.y, uniforms.sourceHeight - 1u);
2925
+ let sourceZ0 = min(sourceBase.z, uniforms.sourceDepth - 1u);
2926
+
2927
+ let sourceX1 = min(sourceBase.x + 1u, uniforms.sourceWidth - 1u);
2928
+ let sourceY1 = min(sourceBase.y + 1u, uniforms.sourceHeight - 1u);
2929
+ let sourceZ1 = min(sourceBase.z + 1u, uniforms.sourceDepth - 1u);
2930
+
2931
+ var sum = textureLoad(
2932
+ sourceTexture,
2933
+ vec3<i32>(i32(sourceX0), i32(sourceY0), i32(sourceZ0)),
2934
+ 0
2935
+ );
2936
+ sum += textureLoad(
2937
+ sourceTexture,
2938
+ vec3<i32>(i32(sourceX1), i32(sourceY0), i32(sourceZ0)),
2939
+ 0
2940
+ );
2941
+ sum += textureLoad(
2942
+ sourceTexture,
2943
+ vec3<i32>(i32(sourceX0), i32(sourceY1), i32(sourceZ0)),
2944
+ 0
2945
+ );
2946
+ sum += textureLoad(
2947
+ sourceTexture,
2948
+ vec3<i32>(i32(sourceX1), i32(sourceY1), i32(sourceZ0)),
2949
+ 0
2950
+ );
2951
+ sum += textureLoad(
2952
+ sourceTexture,
2953
+ vec3<i32>(i32(sourceX0), i32(sourceY0), i32(sourceZ1)),
2954
+ 0
2955
+ );
2956
+ sum += textureLoad(
2957
+ sourceTexture,
2958
+ vec3<i32>(i32(sourceX1), i32(sourceY0), i32(sourceZ1)),
2959
+ 0
2960
+ );
2961
+ sum += textureLoad(
2962
+ sourceTexture,
2963
+ vec3<i32>(i32(sourceX0), i32(sourceY1), i32(sourceZ1)),
2964
+ 0
2965
+ );
2966
+ sum += textureLoad(
2967
+ sourceTexture,
2968
+ vec3<i32>(i32(sourceX1), i32(sourceY1), i32(sourceZ1)),
2969
+ 0
2970
+ );
2971
+
2972
+ textureStore(
2973
+ destinationTexture,
2974
+ vec3<i32>(i32(id.x), i32(id.y), i32(id.z)),
2975
+ vec4<f32>(sum.xyz / 8.0, sum.w / 8.0)
2976
+ );
2977
+ }
2978
+ `;
2979
+ }
2980
+ var import_core24, RENDER_DIMENSIONS, WORKGROUP_SIZE, RENDER_SOURCE_SAMPLER_LAYOUT, COMPUTE_SOURCE_TEXTURE_LAYOUT, COMPUTE_UNIFORMS_LAYOUT;
2981
+ var init_generate_mipmaps_webgpu = __esm({
2982
+ "dist/adapter/helpers/generate-mipmaps-webgpu.js"() {
2983
+ "use strict";
2984
+ import_core24 = require("@luma.gl/core");
2985
+ RENDER_DIMENSIONS = [
2986
+ "2d",
2987
+ "2d-array",
2988
+ "cube",
2989
+ "cube-array"
2990
+ ];
2991
+ WORKGROUP_SIZE = {
2992
+ x: 4,
2993
+ y: 4,
2994
+ z: 4
2995
+ };
2996
+ RENDER_SOURCE_SAMPLER_LAYOUT = {
2997
+ type: "sampler",
2998
+ name: "sourceSampler",
2999
+ group: 0,
3000
+ location: 0
3001
+ };
3002
+ COMPUTE_SOURCE_TEXTURE_LAYOUT = {
3003
+ type: "texture",
3004
+ name: "sourceTexture",
3005
+ group: 0,
3006
+ location: 0,
3007
+ viewDimension: "3d",
3008
+ sampleType: "float"
3009
+ };
3010
+ COMPUTE_UNIFORMS_LAYOUT = {
3011
+ type: "uniform",
3012
+ name: "uniforms",
3013
+ group: 0,
3014
+ location: 2
3015
+ };
3016
+ }
3017
+ });
3018
+
1999
3019
  // dist/adapter/webgpu-device.js
2000
3020
  var webgpu_device_exports = {};
2001
3021
  __export(webgpu_device_exports, {
2002
3022
  WebGPUDevice: () => WebGPUDevice
2003
3023
  });
2004
- var import_core23, WebGPUDevice;
3024
+ function scheduleMicrotask(callback) {
3025
+ if (globalThis.queueMicrotask) {
3026
+ globalThis.queueMicrotask(callback);
3027
+ return;
3028
+ }
3029
+ Promise.resolve().then(callback).catch(() => {
3030
+ });
3031
+ }
3032
+ var import_core25, WebGPUDevice;
2005
3033
  var init_webgpu_device = __esm({
2006
3034
  "dist/adapter/webgpu-device.js"() {
2007
3035
  "use strict";
2008
- import_core23 = require("@luma.gl/core");
3036
+ import_core25 = require("@luma.gl/core");
2009
3037
  init_webgpu_buffer();
2010
3038
  init_webgpu_texture();
2011
3039
  init_webgpu_external_texture();
@@ -2016,12 +3044,15 @@ var init_webgpu_device = __esm({
2016
3044
  init_webgpu_compute_pipeline();
2017
3045
  init_webgpu_vertex_array();
2018
3046
  init_webgpu_canvas_context();
3047
+ init_webgpu_presentation_context();
2019
3048
  init_webgpu_command_encoder();
2020
3049
  init_webgpu_query_set();
2021
3050
  init_webgpu_pipeline_layout();
2022
3051
  init_webgpu_fence();
2023
3052
  init_get_shader_layout_wgsl();
2024
- WebGPUDevice = class extends import_core23.Device {
3053
+ init_generate_mipmaps_webgpu();
3054
+ init_cpu_hotspot_profiler();
3055
+ WebGPUDevice = class extends import_core25.Device {
2025
3056
  /** The underlying WebGPU device */
2026
3057
  handle;
2027
3058
  /* The underlying WebGPU adapter */
@@ -2038,6 +3069,7 @@ var init_webgpu_device = __esm({
2038
3069
  lost;
2039
3070
  canvasContext = null;
2040
3071
  _isLost = false;
3072
+ _defaultSampler = null;
2041
3073
  commandEncoder;
2042
3074
  get [Symbol.toStringTag]() {
2043
3075
  return "WebGPUDevice";
@@ -2064,7 +3096,7 @@ var init_webgpu_device = __esm({
2064
3096
  this._isLost = true;
2065
3097
  resolve({ reason: "destroyed", message: lostInfo.message });
2066
3098
  });
2067
- const canvasContextProps = import_core23.Device._getCanvasContextProps(props);
3099
+ const canvasContextProps = import_core25.Device._getCanvasContextProps(props);
2068
3100
  if (canvasContextProps) {
2069
3101
  this.canvasContext = new WebGPUCanvasContext(this, this.adapter, canvasContextProps);
2070
3102
  }
@@ -2075,6 +3107,10 @@ var init_webgpu_device = __esm({
2075
3107
  // const {glsl = true} = props;
2076
3108
  // this.glslang = glsl && await loadGlslangModule();
2077
3109
  destroy() {
3110
+ var _a, _b;
3111
+ (_a = this.commandEncoder) == null ? void 0 : _a.destroy();
3112
+ (_b = this._defaultSampler) == null ? void 0 : _b.destroy();
3113
+ this._defaultSampler = null;
2078
3114
  this.handle.destroy();
2079
3115
  }
2080
3116
  get isLost() {
@@ -2103,6 +3139,12 @@ var init_webgpu_device = __esm({
2103
3139
  createSampler(props) {
2104
3140
  return new WebGPUSampler(this, props);
2105
3141
  }
3142
+ getDefaultSampler() {
3143
+ this._defaultSampler ||= new WebGPUSampler(this, {
3144
+ id: `${this.id}-default-sampler`
3145
+ });
3146
+ return this._defaultSampler;
3147
+ }
2106
3148
  createRenderPipeline(props) {
2107
3149
  return new WebGPURenderPipeline(this, props);
2108
3150
  }
@@ -2131,32 +3173,106 @@ var init_webgpu_device = __esm({
2131
3173
  createCanvasContext(props) {
2132
3174
  return new WebGPUCanvasContext(this, this.adapter, props);
2133
3175
  }
3176
+ createPresentationContext(props) {
3177
+ return new WebGPUPresentationContext(this, props);
3178
+ }
2134
3179
  createPipelineLayout(props) {
2135
3180
  return new WebGPUPipelineLayout(this, props);
2136
3181
  }
3182
+ generateMipmapsWebGPU(texture) {
3183
+ generateMipmapsWebGPU(this, texture);
3184
+ }
2137
3185
  submit(commandBuffer) {
3186
+ let submittedCommandEncoder = null;
2138
3187
  if (!commandBuffer) {
2139
- commandBuffer = this.commandEncoder.finish();
3188
+ submittedCommandEncoder = this.commandEncoder;
3189
+ if (submittedCommandEncoder.getTimeProfilingSlotCount() > 0 && submittedCommandEncoder.getTimeProfilingQuerySet() instanceof WebGPUQuerySet) {
3190
+ const querySet = submittedCommandEncoder.getTimeProfilingQuerySet();
3191
+ querySet._encodeResolveToReadBuffer(submittedCommandEncoder, {
3192
+ firstQuery: 0,
3193
+ queryCount: submittedCommandEncoder.getTimeProfilingSlotCount()
3194
+ });
3195
+ }
3196
+ commandBuffer = submittedCommandEncoder.finish();
2140
3197
  this.commandEncoder.destroy();
2141
- this.commandEncoder = this.createCommandEncoder({ id: `${this.id}-default-encoder` });
3198
+ this.commandEncoder = this.createCommandEncoder({
3199
+ id: submittedCommandEncoder.props.id,
3200
+ timeProfilingQuerySet: submittedCommandEncoder.getTimeProfilingQuerySet()
3201
+ });
3202
+ }
3203
+ const profiler = getCpuHotspotProfiler(this);
3204
+ const startTime = profiler ? getTimestamp() : 0;
3205
+ const submitReason = getCpuHotspotSubmitReason(this);
3206
+ try {
3207
+ this.pushErrorScope("validation");
3208
+ const queueSubmitStartTime = profiler ? getTimestamp() : 0;
3209
+ this.handle.queue.submit([commandBuffer.handle]);
3210
+ if (profiler) {
3211
+ profiler.queueSubmitCount = (profiler.queueSubmitCount || 0) + 1;
3212
+ profiler.queueSubmitTimeMs = (profiler.queueSubmitTimeMs || 0) + (getTimestamp() - queueSubmitStartTime);
3213
+ }
3214
+ this.popErrorScope((error) => {
3215
+ this.reportError(new Error(`${this} command submission: ${error.message}`), this)();
3216
+ this.debug();
3217
+ });
3218
+ if (submittedCommandEncoder) {
3219
+ const submitResolveKickoffStartTime = profiler ? getTimestamp() : 0;
3220
+ scheduleMicrotask(() => {
3221
+ submittedCommandEncoder.resolveTimeProfilingQuerySet().then(() => {
3222
+ this.commandEncoder._gpuTimeMs = submittedCommandEncoder._gpuTimeMs;
3223
+ }).catch(() => {
3224
+ });
3225
+ });
3226
+ if (profiler) {
3227
+ profiler.submitResolveKickoffCount = (profiler.submitResolveKickoffCount || 0) + 1;
3228
+ profiler.submitResolveKickoffTimeMs = (profiler.submitResolveKickoffTimeMs || 0) + (getTimestamp() - submitResolveKickoffStartTime);
3229
+ }
3230
+ }
3231
+ } finally {
3232
+ if (profiler) {
3233
+ profiler.submitCount = (profiler.submitCount || 0) + 1;
3234
+ profiler.submitTimeMs = (profiler.submitTimeMs || 0) + (getTimestamp() - startTime);
3235
+ const reasonCountKey = submitReason === "query-readback" ? "queryReadbackSubmitCount" : "defaultSubmitCount";
3236
+ const reasonTimeKey = submitReason === "query-readback" ? "queryReadbackSubmitTimeMs" : "defaultSubmitTimeMs";
3237
+ profiler[reasonCountKey] = (profiler[reasonCountKey] || 0) + 1;
3238
+ profiler[reasonTimeKey] = (profiler[reasonTimeKey] || 0) + (getTimestamp() - startTime);
3239
+ }
3240
+ const commandBufferDestroyStartTime = profiler ? getTimestamp() : 0;
3241
+ commandBuffer.destroy();
3242
+ if (profiler) {
3243
+ profiler.commandBufferDestroyCount = (profiler.commandBufferDestroyCount || 0) + 1;
3244
+ profiler.commandBufferDestroyTimeMs = (profiler.commandBufferDestroyTimeMs || 0) + (getTimestamp() - commandBufferDestroyStartTime);
3245
+ }
2142
3246
  }
2143
- this.pushErrorScope("validation");
2144
- this.handle.queue.submit([commandBuffer.handle]);
2145
- this.popErrorScope((error) => {
2146
- this.reportError(new Error(`${this} command submission: ${error.message}`), this)();
2147
- this.debug();
2148
- });
2149
3247
  }
2150
3248
  // WebGPU specific
2151
3249
  pushErrorScope(scope) {
3250
+ if (!this.props.debug) {
3251
+ return;
3252
+ }
3253
+ const profiler = getCpuHotspotProfiler(this);
3254
+ const startTime = profiler ? getTimestamp() : 0;
2152
3255
  this.handle.pushErrorScope(scope);
3256
+ if (profiler) {
3257
+ profiler.errorScopePushCount = (profiler.errorScopePushCount || 0) + 1;
3258
+ profiler.errorScopeTimeMs = (profiler.errorScopeTimeMs || 0) + (getTimestamp() - startTime);
3259
+ }
2153
3260
  }
2154
3261
  popErrorScope(handler) {
3262
+ if (!this.props.debug) {
3263
+ return;
3264
+ }
3265
+ const profiler = getCpuHotspotProfiler(this);
3266
+ const startTime = profiler ? getTimestamp() : 0;
2155
3267
  this.handle.popErrorScope().then((error) => {
2156
3268
  if (error) {
2157
3269
  handler(error);
2158
3270
  }
2159
3271
  });
3272
+ if (profiler) {
3273
+ profiler.errorScopePopCount = (profiler.errorScopePopCount || 0) + 1;
3274
+ profiler.errorScopeTimeMs = (profiler.errorScopeTimeMs || 0) + (getTimestamp() - startTime);
3275
+ }
2160
3276
  }
2161
3277
  // PRIVATE METHODS
2162
3278
  _getInfo() {
@@ -2197,7 +3313,6 @@ var init_webgpu_device = __esm({
2197
3313
  features.add("snorm16-renderable-webgl");
2198
3314
  }
2199
3315
  const WEBGPU_ALWAYS_FEATURES = [
2200
- "timer-query-webgl",
2201
3316
  "compilation-status-async-webgl",
2202
3317
  "float32-renderable-webgl",
2203
3318
  "float16-renderable-webgl",
@@ -2208,7 +3323,7 @@ var init_webgpu_device = __esm({
2208
3323
  for (const feature of WEBGPU_ALWAYS_FEATURES) {
2209
3324
  features.add(feature);
2210
3325
  }
2211
- return new import_core23.DeviceFeatures(Array.from(features), this.props._disabledFeatures);
3326
+ return new import_core25.DeviceFeatures(Array.from(features), this.props._disabledFeatures);
2212
3327
  }
2213
3328
  _getDeviceSpecificTextureFormatCapabilities(capabilities) {
2214
3329
  const { format } = capabilities;
@@ -2236,8 +3351,8 @@ __export(dist_exports, {
2236
3351
  module.exports = __toCommonJS(dist_exports);
2237
3352
 
2238
3353
  // dist/adapter/webgpu-adapter.js
2239
- var import_core24 = require("@luma.gl/core");
2240
- var WebGPUAdapter = class extends import_core24.Adapter {
3354
+ var import_core26 = require("@luma.gl/core");
3355
+ var WebGPUAdapter = class extends import_core26.Adapter {
2241
3356
  /** type of device's created by this adapter */
2242
3357
  type = "webgpu";
2243
3358
  isSupported() {
@@ -2284,14 +3399,14 @@ var WebGPUAdapter = class extends import_core24.Adapter {
2284
3399
  requiredLimits
2285
3400
  });
2286
3401
  const { WebGPUDevice: WebGPUDevice2 } = await Promise.resolve().then(() => (init_webgpu_device(), webgpu_device_exports));
2287
- import_core24.log.groupCollapsed(1, "WebGPUDevice created")();
3402
+ import_core26.log.groupCollapsed(1, "WebGPUDevice created")();
2288
3403
  try {
2289
3404
  const device = new WebGPUDevice2(props, gpuDevice, adapter, adapterInfo);
2290
- import_core24.log.probe(1, "Device created. For more info, set chrome://flags/#enable-webgpu-developer-features")();
2291
- import_core24.log.table(1, device.info)();
3405
+ import_core26.log.probe(1, "Device created. For more info, set chrome://flags/#enable-webgpu-developer-features")();
3406
+ import_core26.log.table(1, device.info)();
2292
3407
  return device;
2293
3408
  } finally {
2294
- import_core24.log.groupEnd(1)();
3409
+ import_core26.log.groupEnd(1)();
2295
3410
  }
2296
3411
  }
2297
3412
  async attach(handle) {