@luma.gl/engine 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 (88) hide show
  1. package/dist/animation-loop/animation-loop.d.ts +8 -4
  2. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  3. package/dist/animation-loop/animation-loop.js +70 -43
  4. package/dist/animation-loop/animation-loop.js.map +1 -1
  5. package/dist/animation-loop/make-animation-loop.js +7 -1
  6. package/dist/animation-loop/make-animation-loop.js.map +1 -1
  7. package/dist/animation-loop/request-animation-frame.d.ts.map +1 -1
  8. package/dist/animation-loop/request-animation-frame.js +23 -6
  9. package/dist/animation-loop/request-animation-frame.js.map +1 -1
  10. package/dist/dist.dev.js +679 -927
  11. package/dist/dist.min.js +39 -240
  12. package/dist/dynamic-texture/dynamic-texture.d.ts +3 -3
  13. package/dist/dynamic-texture/dynamic-texture.d.ts.map +1 -1
  14. package/dist/dynamic-texture/dynamic-texture.js +170 -52
  15. package/dist/dynamic-texture/dynamic-texture.js.map +1 -1
  16. package/dist/dynamic-texture/texture-data.d.ts +4 -0
  17. package/dist/dynamic-texture/texture-data.d.ts.map +1 -1
  18. package/dist/dynamic-texture/texture-data.js +8 -0
  19. package/dist/dynamic-texture/texture-data.js.map +1 -1
  20. package/dist/factories/pipeline-factory.d.ts +7 -5
  21. package/dist/factories/pipeline-factory.d.ts.map +1 -1
  22. package/dist/factories/pipeline-factory.js +71 -36
  23. package/dist/factories/pipeline-factory.js.map +1 -1
  24. package/dist/factories/shader-factory.d.ts +0 -3
  25. package/dist/factories/shader-factory.d.ts.map +1 -1
  26. package/dist/factories/shader-factory.js +13 -19
  27. package/dist/factories/shader-factory.js.map +1 -1
  28. package/dist/geometries/cone-geometry.d.ts +3 -1
  29. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  30. package/dist/geometries/cone-geometry.js.map +1 -1
  31. package/dist/geometries/cylinder-geometry.d.ts +2 -1
  32. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  33. package/dist/geometries/cylinder-geometry.js.map +1 -1
  34. package/dist/index.cjs +683 -922
  35. package/dist/index.cjs.map +4 -4
  36. package/dist/model/model.d.ts +3 -1
  37. package/dist/model/model.d.ts.map +1 -1
  38. package/dist/model/model.js +11 -9
  39. package/dist/model/model.js.map +1 -1
  40. package/dist/models/billboard-texture-model.d.ts.map +1 -1
  41. package/dist/models/billboard-texture-model.js +10 -8
  42. package/dist/models/billboard-texture-model.js.map +1 -1
  43. package/dist/models/clip-space.js +7 -7
  44. package/dist/modules/picking/index-picking.d.ts +1 -1
  45. package/dist/modules/picking/index-picking.d.ts.map +1 -1
  46. package/dist/modules/picking/index-picking.js +0 -6
  47. package/dist/modules/picking/index-picking.js.map +1 -1
  48. package/dist/passes/get-fragment-shader.js +11 -30
  49. package/dist/passes/get-fragment-shader.js.map +1 -1
  50. package/dist/passes/shader-pass-renderer.d.ts +0 -2
  51. package/dist/passes/shader-pass-renderer.d.ts.map +1 -1
  52. package/dist/passes/shader-pass-renderer.js +4 -31
  53. package/dist/passes/shader-pass-renderer.js.map +1 -1
  54. package/dist/scenegraph/group-node.d.ts +5 -0
  55. package/dist/scenegraph/group-node.d.ts.map +1 -1
  56. package/dist/scenegraph/group-node.js +12 -0
  57. package/dist/scenegraph/group-node.js.map +1 -1
  58. package/dist/scenegraph/model-node.d.ts +2 -2
  59. package/dist/scenegraph/model-node.d.ts.map +1 -1
  60. package/dist/scenegraph/model-node.js.map +1 -1
  61. package/dist/scenegraph/scenegraph-node.d.ts +1 -1
  62. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
  63. package/dist/scenegraph/scenegraph-node.js +23 -15
  64. package/dist/scenegraph/scenegraph-node.js.map +1 -1
  65. package/package.json +2 -2
  66. package/src/animation-loop/animation-loop.ts +75 -46
  67. package/src/animation-loop/make-animation-loop.ts +13 -5
  68. package/src/animation-loop/request-animation-frame.ts +32 -6
  69. package/src/dynamic-texture/dynamic-texture.ts +226 -65
  70. package/src/dynamic-texture/texture-data.ts +14 -0
  71. package/src/factories/pipeline-factory.ts +87 -46
  72. package/src/factories/shader-factory.ts +16 -20
  73. package/src/geometries/cone-geometry.ts +6 -1
  74. package/src/geometries/cylinder-geometry.ts +5 -1
  75. package/src/model/model.ts +14 -10
  76. package/src/models/billboard-texture-model.ts +10 -8
  77. package/src/models/clip-space.ts +7 -7
  78. package/src/modules/picking/index-picking.ts +0 -6
  79. package/src/passes/get-fragment-shader.ts +11 -30
  80. package/src/passes/shader-pass-renderer.ts +4 -33
  81. package/src/scenegraph/group-node.ts +16 -0
  82. package/src/scenegraph/model-node.ts +2 -2
  83. package/src/scenegraph/scenegraph-node.ts +27 -16
  84. package/dist/dynamic-texture/mipmaps.d.ts +0 -6
  85. package/dist/dynamic-texture/mipmaps.d.ts.map +0 -1
  86. package/dist/dynamic-texture/mipmaps.js +0 -441
  87. package/dist/dynamic-texture/mipmaps.js.map +0 -1
  88. package/src/dynamic-texture/mipmaps.ts +0 -517
package/dist/index.cjs CHANGED
@@ -246,15 +246,25 @@ var import_core = require("@luma.gl/core");
246
246
 
247
247
  // dist/animation-loop/request-animation-frame.js
248
248
  function requestAnimationFramePolyfill(callback) {
249
- return typeof window !== "undefined" && window.requestAnimationFrame ? window.requestAnimationFrame(callback) : setTimeout(callback, 1e3 / 60);
249
+ const browserRequestAnimationFrame = typeof window !== "undefined" ? window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame : null;
250
+ if (browserRequestAnimationFrame) {
251
+ return browserRequestAnimationFrame.call(window, callback);
252
+ }
253
+ return setTimeout(() => callback(typeof performance !== "undefined" ? performance.now() : Date.now()), 1e3 / 60);
250
254
  }
251
255
  function cancelAnimationFramePolyfill(timerId) {
252
- return typeof window !== "undefined" && window.cancelAnimationFrame ? window.cancelAnimationFrame(timerId) : clearTimeout(timerId);
256
+ const browserCancelAnimationFrame = typeof window !== "undefined" ? window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame : null;
257
+ if (browserCancelAnimationFrame) {
258
+ browserCancelAnimationFrame.call(window, timerId);
259
+ return;
260
+ }
261
+ clearTimeout(timerId);
253
262
  }
254
263
 
255
264
  // dist/animation-loop/animation-loop.js
256
265
  var import_stats = require("@probe.gl/stats");
257
266
  var statIdCounter = 0;
267
+ var ANIMATION_LOOP_STATS = "Animation Loop";
258
268
  var _AnimationLoop = class {
259
269
  device = null;
260
270
  canvas = null;
@@ -262,6 +272,7 @@ var _AnimationLoop = class {
262
272
  animationProps = null;
263
273
  timeline = null;
264
274
  stats;
275
+ sharedStats;
265
276
  cpuTime;
266
277
  gpuTime;
267
278
  frameRate;
@@ -274,7 +285,7 @@ var _AnimationLoop = class {
274
285
  _resolveNextFrame = null;
275
286
  _cpuStartTime = 0;
276
287
  _error = null;
277
- // _gpuTimeQuery: Query | null = null;
288
+ _lastFrameTime = 0;
278
289
  /*
279
290
  * @param {HTMLCanvasElement} canvas - if provided, width and height will be passed to context
280
291
  */
@@ -284,10 +295,12 @@ var _AnimationLoop = class {
284
295
  if (!props.device) {
285
296
  throw new Error("No device provided");
286
297
  }
287
- this.stats = props.stats || new import_stats.Stats({ id: "animation-loop-stats" });
298
+ this.stats = props.stats || new import_stats.Stats({ id: `animation-loop-${statIdCounter++}` });
299
+ this.sharedStats = import_core.luma.stats.get(ANIMATION_LOOP_STATS);
300
+ this.frameRate = this.stats.get("Frame Rate");
301
+ this.frameRate.setSampleSize(1);
288
302
  this.cpuTime = this.stats.get("CPU Time");
289
303
  this.gpuTime = this.stats.get("GPU Time");
290
- this.frameRate = this.stats.get("Frame Rate");
291
304
  this.setProps({ autoResizeViewport: props.autoResizeViewport });
292
305
  this.start = this.start.bind(this);
293
306
  this.stop = this.stop.bind(this);
@@ -295,8 +308,10 @@ var _AnimationLoop = class {
295
308
  this._onMouseleave = this._onMouseleave.bind(this);
296
309
  }
297
310
  destroy() {
311
+ var _a;
298
312
  this.stop();
299
313
  this._setDisplay(null);
314
+ (_a = this.device) == null ? void 0 : _a._disableDebugGPUTime();
300
315
  }
301
316
  /** @deprecated Use .destroy() */
302
317
  delete() {
@@ -361,16 +376,17 @@ var _AnimationLoop = class {
361
376
  this._nextFramePromise = null;
362
377
  this._resolveNextFrame = null;
363
378
  this._running = false;
379
+ this._lastFrameTime = 0;
364
380
  }
365
381
  return this;
366
382
  }
367
383
  /** Explicitly draw a frame */
368
- redraw() {
384
+ redraw(time) {
369
385
  var _a;
370
386
  if (((_a = this.device) == null ? void 0 : _a.isLost) || this._error) {
371
387
  return this;
372
388
  }
373
- this._beginFrameTimers();
389
+ this._beginFrameTimers(time);
374
390
  this._setupFrame();
375
391
  this._updateAnimationProps();
376
392
  this._renderFrame(this._getAnimationProps());
@@ -413,10 +429,12 @@ var _AnimationLoop = class {
413
429
  }
414
430
  // PRIVATE METHODS
415
431
  _initialize() {
432
+ var _a;
416
433
  this._startEventHandling();
417
434
  this._initializeAnimationProps();
418
435
  this._updateAnimationProps();
419
436
  this._resizeViewport();
437
+ (_a = this.device) == null ? void 0 : _a._enableDebugGPUTime();
420
438
  }
421
439
  _setDisplay(display) {
422
440
  if (this.display) {
@@ -441,11 +459,11 @@ var _AnimationLoop = class {
441
459
  cancelAnimationFramePolyfill(this._animationFrameId);
442
460
  this._animationFrameId = null;
443
461
  }
444
- _animationFrame() {
462
+ _animationFrame(time) {
445
463
  if (!this._running) {
446
464
  return;
447
465
  }
448
- this.redraw();
466
+ this.redraw(time);
449
467
  this._requestAnimationFrame();
450
468
  }
451
469
  // Called on each frame, can be overridden to call onRender multiple times
@@ -558,18 +576,11 @@ var _AnimationLoop = class {
558
576
  }
559
577
  }
560
578
  _getSizeAndAspect() {
561
- var _a, _b;
562
579
  if (!this.device) {
563
580
  return { width: 1, height: 1, aspect: 1 };
564
581
  }
565
- const [width, height] = ((_a = this.device) == null ? void 0 : _a.getDefaultCanvasContext().getDevicePixelSize()) || [1, 1];
566
- let aspect = 1;
567
- const canvas2 = (_b = this.device) == null ? void 0 : _b.getDefaultCanvasContext().canvas;
568
- if (canvas2 && canvas2.clientHeight) {
569
- aspect = canvas2.clientWidth / canvas2.clientHeight;
570
- } else if (width > 0 && height > 0) {
571
- aspect = width / height;
572
- }
582
+ const [width, height] = this.device.getDefaultCanvasContext().getDrawingBufferSize();
583
+ const aspect = width > 0 && height > 0 ? width / height : 1;
573
584
  return { width, height, aspect };
574
585
  }
575
586
  /** @deprecated Default viewport setup */
@@ -585,13 +596,63 @@ var _AnimationLoop = class {
585
596
  );
586
597
  }
587
598
  }
588
- _beginFrameTimers() {
589
- this.frameRate.timeEnd();
590
- this.frameRate.timeStart();
599
+ _beginFrameTimers(time) {
600
+ var _a;
601
+ const now = time ?? (typeof performance !== "undefined" ? performance.now() : Date.now());
602
+ if (this._lastFrameTime) {
603
+ const frameTime = now - this._lastFrameTime;
604
+ if (frameTime > 0) {
605
+ this.frameRate.addTime(frameTime);
606
+ }
607
+ }
608
+ this._lastFrameTime = now;
609
+ if ((_a = this.device) == null ? void 0 : _a._isDebugGPUTimeEnabled()) {
610
+ this._consumeEncodedGpuTime();
611
+ }
591
612
  this.cpuTime.timeStart();
592
613
  }
593
614
  _endFrameTimers() {
615
+ var _a;
616
+ if ((_a = this.device) == null ? void 0 : _a._isDebugGPUTimeEnabled()) {
617
+ this._consumeEncodedGpuTime();
618
+ }
594
619
  this.cpuTime.timeEnd();
620
+ this._updateSharedStats();
621
+ }
622
+ _consumeEncodedGpuTime() {
623
+ if (!this.device) {
624
+ return;
625
+ }
626
+ const gpuTimeMs = this.device.commandEncoder._gpuTimeMs;
627
+ if (gpuTimeMs !== void 0) {
628
+ this.gpuTime.addTime(gpuTimeMs);
629
+ this.device.commandEncoder._gpuTimeMs = void 0;
630
+ }
631
+ }
632
+ _updateSharedStats() {
633
+ if (this.stats === this.sharedStats) {
634
+ return;
635
+ }
636
+ for (const name of Object.keys(this.sharedStats.stats)) {
637
+ if (!this.stats.stats[name]) {
638
+ delete this.sharedStats.stats[name];
639
+ }
640
+ }
641
+ this.stats.forEach((sourceStat) => {
642
+ const targetStat = this.sharedStats.get(sourceStat.name, sourceStat.type);
643
+ targetStat.sampleSize = sourceStat.sampleSize;
644
+ targetStat.time = sourceStat.time;
645
+ targetStat.count = sourceStat.count;
646
+ targetStat.samples = sourceStat.samples;
647
+ targetStat.lastTiming = sourceStat.lastTiming;
648
+ targetStat.lastSampleTime = sourceStat.lastSampleTime;
649
+ targetStat.lastSampleCount = sourceStat.lastSampleCount;
650
+ targetStat._count = sourceStat._count;
651
+ targetStat._time = sourceStat._time;
652
+ targetStat._samples = sourceStat._samples;
653
+ targetStat._startTime = sourceStat._startTime;
654
+ targetStat._timerPending = sourceStat._timerPending;
655
+ });
595
656
  }
596
657
  // Event handling
597
658
  _startEventHandling() {
@@ -620,7 +681,7 @@ __publicField(AnimationLoop, "defaultAnimationLoopProps", {
620
681
  },
621
682
  onError: (error) => console.error(error),
622
683
  // eslint-disable-line no-console
623
- stats: import_core.luma.stats.get(`animation-loop-${statIdCounter++}`),
684
+ stats: void 0,
624
685
  // view parameters
625
686
  autoResizeViewport: false
626
687
  });
@@ -653,7 +714,10 @@ function makeAnimationLoop(AnimationLoopTemplateCtor, props) {
653
714
  }
654
715
  function setError(device, error) {
655
716
  var _a;
656
- const canvas2 = device == null ? void 0 : device.getDefaultCanvasContext().canvas;
717
+ if (!device) {
718
+ return;
719
+ }
720
+ const canvas2 = device.getDefaultCanvasContext().canvas;
657
721
  if (canvas2 instanceof HTMLCanvasElement) {
658
722
  canvas2.style.overflow = "visible";
659
723
  let errorDiv = document.getElementById("animation-loop-error");
@@ -670,6 +734,9 @@ function setError(device, error) {
670
734
  }
671
735
  }
672
736
  function clearError(device) {
737
+ if (!device) {
738
+ return;
739
+ }
673
740
  const errorDiv = document.getElementById("animation-loop-error");
674
741
  if (errorDiv) {
675
742
  errorDiv.remove();
@@ -677,8 +744,8 @@ function clearError(device) {
677
744
  }
678
745
 
679
746
  // dist/model/model.js
680
- var import_core12 = require("@luma.gl/core");
681
- var import_shadertools3 = require("@luma.gl/shadertools");
747
+ var import_core10 = require("@luma.gl/core");
748
+ var import_shadertools2 = require("@luma.gl/shadertools");
682
749
 
683
750
  // dist/geometry/gpu-geometry.js
684
751
  var import_core3 = require("@luma.gl/core");
@@ -798,13 +865,11 @@ var _PipelineFactory = class {
798
865
  return moduleData.defaultPipelineFactory;
799
866
  }
800
867
  device;
801
- cachingEnabled;
802
- destroyPolicy;
803
- debug;
804
868
  _hashCounter = 0;
805
869
  _hashes = {};
806
870
  _renderPipelineCache = {};
807
871
  _computePipelineCache = {};
872
+ _sharedRenderPipelineCache = {};
808
873
  get [Symbol.toStringTag]() {
809
874
  return "PipelineFactory";
810
875
  }
@@ -813,34 +878,33 @@ var _PipelineFactory = class {
813
878
  }
814
879
  constructor(device) {
815
880
  this.device = device;
816
- this.cachingEnabled = device.props._cachePipelines;
817
- this.destroyPolicy = device.props._cacheDestroyPolicy;
818
- this.debug = device.props.debugFactories;
819
881
  }
820
882
  /** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
821
883
  createRenderPipeline(props) {
822
884
  var _a;
823
- if (!this.cachingEnabled) {
885
+ if (!this.device.props._cachePipelines) {
824
886
  return this.device.createRenderPipeline(props);
825
887
  }
826
888
  const allProps = { ...import_core4.RenderPipeline.defaultProps, ...props };
827
889
  const cache = this._renderPipelineCache;
828
890
  const hash = this._hashRenderPipeline(allProps);
829
- let pipeline = (_a = cache[hash]) == null ? void 0 : _a.pipeline;
891
+ let pipeline = (_a = cache[hash]) == null ? void 0 : _a.resource;
830
892
  if (!pipeline) {
893
+ const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
831
894
  pipeline = this.device.createRenderPipeline({
832
895
  ...allProps,
833
- id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached")
896
+ id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
897
+ _sharedRenderPipeline: sharedRenderPipeline
834
898
  });
835
899
  pipeline.hash = hash;
836
- cache[hash] = { pipeline, useCount: 1 };
837
- if (this.debug) {
900
+ cache[hash] = { resource: pipeline, useCount: 1 };
901
+ if (this.device.props.debugFactories) {
838
902
  import_core4.log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
839
903
  }
840
904
  } else {
841
905
  cache[hash].useCount++;
842
- if (this.debug) {
843
- import_core4.log.log(3, `${this}: ${cache[hash].pipeline} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
906
+ if (this.device.props.debugFactories) {
907
+ import_core4.log.log(3, `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
844
908
  }
845
909
  }
846
910
  return pipeline;
@@ -848,33 +912,33 @@ var _PipelineFactory = class {
848
912
  /** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
849
913
  createComputePipeline(props) {
850
914
  var _a;
851
- if (!this.cachingEnabled) {
915
+ if (!this.device.props._cachePipelines) {
852
916
  return this.device.createComputePipeline(props);
853
917
  }
854
918
  const allProps = { ...import_core4.ComputePipeline.defaultProps, ...props };
855
919
  const cache = this._computePipelineCache;
856
920
  const hash = this._hashComputePipeline(allProps);
857
- let pipeline = (_a = cache[hash]) == null ? void 0 : _a.pipeline;
921
+ let pipeline = (_a = cache[hash]) == null ? void 0 : _a.resource;
858
922
  if (!pipeline) {
859
923
  pipeline = this.device.createComputePipeline({
860
924
  ...allProps,
861
925
  id: allProps.id ? `${allProps.id}-cached` : void 0
862
926
  });
863
927
  pipeline.hash = hash;
864
- cache[hash] = { pipeline, useCount: 1 };
865
- if (this.debug) {
928
+ cache[hash] = { resource: pipeline, useCount: 1 };
929
+ if (this.device.props.debugFactories) {
866
930
  import_core4.log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
867
931
  }
868
932
  } else {
869
933
  cache[hash].useCount++;
870
- if (this.debug) {
871
- import_core4.log.log(3, `${this}: ${cache[hash].pipeline} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
934
+ if (this.device.props.debugFactories) {
935
+ import_core4.log.log(3, `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
872
936
  }
873
937
  }
874
938
  return pipeline;
875
939
  }
876
940
  release(pipeline) {
877
- if (!this.cachingEnabled) {
941
+ if (!this.device.props._cachePipelines) {
878
942
  pipeline.destroy();
879
943
  return;
880
944
  }
@@ -883,28 +947,55 @@ var _PipelineFactory = class {
883
947
  cache[hash].useCount--;
884
948
  if (cache[hash].useCount === 0) {
885
949
  this._destroyPipeline(pipeline);
886
- if (this.debug) {
950
+ if (this.device.props.debugFactories) {
887
951
  import_core4.log.log(3, `${this}: ${pipeline} released and destroyed`)();
888
952
  }
889
953
  } else if (cache[hash].useCount < 0) {
890
954
  import_core4.log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
891
955
  cache[hash].useCount = 0;
892
- } else if (this.debug) {
956
+ } else if (this.device.props.debugFactories) {
893
957
  import_core4.log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
894
958
  }
895
959
  }
960
+ createSharedRenderPipeline(props) {
961
+ const sharedPipelineHash = this._hashSharedRenderPipeline(props);
962
+ let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
963
+ if (!sharedCacheItem) {
964
+ const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
965
+ sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
966
+ this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
967
+ }
968
+ sharedCacheItem.useCount++;
969
+ return sharedCacheItem.resource;
970
+ }
971
+ releaseSharedRenderPipeline(pipeline) {
972
+ if (!pipeline.sharedRenderPipeline) {
973
+ return;
974
+ }
975
+ const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
976
+ const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
977
+ if (!sharedCacheItem) {
978
+ return;
979
+ }
980
+ sharedCacheItem.useCount--;
981
+ if (sharedCacheItem.useCount === 0) {
982
+ sharedCacheItem.resource.destroy();
983
+ delete this._sharedRenderPipelineCache[sharedPipelineHash];
984
+ }
985
+ }
896
986
  // PRIVATE
897
- /** Destroy a cached pipeline, removing it from the cache (depending on destroy policy) */
987
+ /** Destroy a cached pipeline, removing it from the cache if configured to do so. */
898
988
  _destroyPipeline(pipeline) {
899
989
  const cache = this._getCache(pipeline);
900
- switch (this.destroyPolicy) {
901
- case "never":
902
- return false;
903
- case "unused":
904
- delete cache[pipeline.hash];
905
- pipeline.destroy();
906
- return true;
990
+ if (!this.device.props._destroyPipelines) {
991
+ return false;
992
+ }
993
+ delete cache[pipeline.hash];
994
+ pipeline.destroy();
995
+ if (pipeline instanceof import_core4.RenderPipeline) {
996
+ this.releaseSharedRenderPipeline(pipeline);
907
997
  }
998
+ return true;
908
999
  }
909
1000
  /** Get the appropriate cache for the type of pipeline */
910
1001
  _getCache(pipeline) {
@@ -933,24 +1024,35 @@ var _PipelineFactory = class {
933
1024
  _hashRenderPipeline(props) {
934
1025
  const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
935
1026
  const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
936
- const varyingHash = "-";
1027
+ const varyingHash = this._getWebGLVaryingHash(props);
937
1028
  const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
938
1029
  const { type } = this.device;
939
1030
  switch (type) {
940
1031
  case "webgl":
941
- return `${type}/R/${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
1032
+ const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
1033
+ return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}BL${bufferLayoutHash}`;
942
1034
  case "webgpu":
943
1035
  default:
944
1036
  const parameterHash = this._getHash(JSON.stringify(props.parameters));
945
1037
  return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
946
1038
  }
947
1039
  }
1040
+ _hashSharedRenderPipeline(props) {
1041
+ const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
1042
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
1043
+ const varyingHash = this._getWebGLVaryingHash(props);
1044
+ return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
1045
+ }
948
1046
  _getHash(key) {
949
1047
  if (this._hashes[key] === void 0) {
950
1048
  this._hashes[key] = this._hashCounter++;
951
1049
  }
952
1050
  return this._hashes[key];
953
1051
  }
1052
+ _getWebGLVaryingHash(props) {
1053
+ const { varyings = [], bufferMode = null } = props;
1054
+ return this._getHash(JSON.stringify({ varyings, bufferMode }));
1055
+ }
954
1056
  };
955
1057
  var PipelineFactory = _PipelineFactory;
956
1058
  __publicField(PipelineFactory, "defaultProps", { ...import_core4.RenderPipeline.defaultProps });
@@ -965,9 +1067,6 @@ var _ShaderFactory = class {
965
1067
  return moduleData.defaultShaderFactory;
966
1068
  }
967
1069
  device;
968
- cachingEnabled;
969
- destroyPolicy;
970
- debug;
971
1070
  _cache = {};
972
1071
  get [Symbol.toStringTag]() {
973
1072
  return "ShaderFactory";
@@ -978,37 +1077,34 @@ var _ShaderFactory = class {
978
1077
  /** @internal */
979
1078
  constructor(device) {
980
1079
  this.device = device;
981
- this.cachingEnabled = device.props._cacheShaders;
982
- this.destroyPolicy = device.props._cacheDestroyPolicy;
983
- this.debug = true;
984
1080
  }
985
1081
  /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
986
1082
  createShader(props) {
987
- if (!this.cachingEnabled) {
1083
+ if (!this.device.props._cacheShaders) {
988
1084
  return this.device.createShader(props);
989
1085
  }
990
1086
  const key = this._hashShader(props);
991
1087
  let cacheEntry = this._cache[key];
992
1088
  if (!cacheEntry) {
993
- const shader = this.device.createShader({
1089
+ const resource = this.device.createShader({
994
1090
  ...props,
995
1091
  id: props.id ? `${props.id}-cached` : void 0
996
1092
  });
997
- this._cache[key] = cacheEntry = { shader, useCount: 1 };
998
- if (this.debug) {
999
- import_core5.log.log(3, `${this}: Created new shader ${shader.id}`)();
1093
+ this._cache[key] = cacheEntry = { resource, useCount: 1 };
1094
+ if (this.device.props.debugFactories) {
1095
+ import_core5.log.log(3, `${this}: Created new shader ${resource.id}`)();
1000
1096
  }
1001
1097
  } else {
1002
1098
  cacheEntry.useCount++;
1003
- if (this.debug) {
1004
- import_core5.log.log(3, `${this}: Reusing shader ${cacheEntry.shader.id} count=${cacheEntry.useCount}`)();
1099
+ if (this.device.props.debugFactories) {
1100
+ import_core5.log.log(3, `${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`)();
1005
1101
  }
1006
1102
  }
1007
- return cacheEntry.shader;
1103
+ return cacheEntry.resource;
1008
1104
  }
1009
1105
  /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
1010
1106
  release(shader) {
1011
- if (!this.cachingEnabled) {
1107
+ if (!this.device.props._cacheShaders) {
1012
1108
  shader.destroy();
1013
1109
  return;
1014
1110
  }
@@ -1017,16 +1113,16 @@ var _ShaderFactory = class {
1017
1113
  if (cacheEntry) {
1018
1114
  cacheEntry.useCount--;
1019
1115
  if (cacheEntry.useCount === 0) {
1020
- if (this.destroyPolicy === "unused") {
1116
+ if (this.device.props._destroyShaders) {
1021
1117
  delete this._cache[key];
1022
- cacheEntry.shader.destroy();
1023
- if (this.debug) {
1118
+ cacheEntry.resource.destroy();
1119
+ if (this.device.props.debugFactories) {
1024
1120
  import_core5.log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
1025
1121
  }
1026
1122
  }
1027
1123
  } else if (cacheEntry.useCount < 0) {
1028
1124
  throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
1029
- } else if (this.debug) {
1125
+ } else if (this.device.props.debugFactories) {
1030
1126
  import_core5.log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
1031
1127
  }
1032
1128
  }
@@ -1326,7 +1422,7 @@ var ShaderInputs = class {
1326
1422
  };
1327
1423
 
1328
1424
  // dist/dynamic-texture/dynamic-texture.js
1329
- var import_core11 = require("@luma.gl/core");
1425
+ var import_core9 = require("@luma.gl/core");
1330
1426
 
1331
1427
  // dist/dynamic-texture/texture-data.js
1332
1428
  var import_core8 = require("@luma.gl/core");
@@ -1394,6 +1490,13 @@ function getTextureMipLevelSize(data) {
1394
1490
  function isTextureImageData(data) {
1395
1491
  return typeof data === "object" && data !== null && "data" in data && "width" in data && "height" in data;
1396
1492
  }
1493
+ function resolveTextureImageFormat(data) {
1494
+ const { textureFormat, format } = data;
1495
+ if (textureFormat && format && textureFormat !== format) {
1496
+ throw new Error(`Conflicting texture formats "${textureFormat}" and "${format}" provided for the same mip level`);
1497
+ }
1498
+ return textureFormat ?? format;
1499
+ }
1397
1500
  function getCubeFaceIndex(face) {
1398
1501
  const idx = TEXTURE_CUBE_FACE_MAP[face];
1399
1502
  if (idx === void 0)
@@ -1426,6 +1529,7 @@ function getTexture2DSubresources(slice, lodData) {
1426
1529
  subresources.push({
1427
1530
  type: "texture-data",
1428
1531
  data: imageData,
1532
+ textureFormat: resolveTextureImageFormat(imageData),
1429
1533
  z,
1430
1534
  mipLevel
1431
1535
  });
@@ -1468,641 +1572,6 @@ function getTextureCubeArraySubresources(data) {
1468
1572
  return subresources;
1469
1573
  }
1470
1574
 
1471
- // dist/dynamic-texture/mipmaps.js
1472
- var import_core10 = require("@luma.gl/core");
1473
-
1474
- // dist/compute/computation.js
1475
- var import_core9 = require("@luma.gl/core");
1476
- var import_shadertools2 = require("@luma.gl/shadertools");
1477
- var import_types2 = require("@math.gl/types");
1478
- var LOG_DRAW_PRIORITY = 2;
1479
- var LOG_DRAW_TIMEOUT = 1e4;
1480
- var _Computation = class {
1481
- device;
1482
- id;
1483
- pipelineFactory;
1484
- shaderFactory;
1485
- userData = {};
1486
- /** Bindings (textures, samplers, uniform buffers) */
1487
- bindings = {};
1488
- /** The underlying GPU pipeline. */
1489
- pipeline;
1490
- /** Assembled compute shader source */
1491
- source;
1492
- /** the underlying compiled compute shader */
1493
- // @ts-ignore Set in function called from constructor
1494
- shader;
1495
- /** ShaderInputs instance */
1496
- shaderInputs;
1497
- // @ts-ignore Set in function called from constructor
1498
- _uniformStore;
1499
- _pipelineNeedsUpdate = "newly created";
1500
- _getModuleUniforms;
1501
- props;
1502
- _destroyed = false;
1503
- constructor(device, props) {
1504
- var _a, _b, _c;
1505
- if (device.type !== "webgpu") {
1506
- throw new Error("Computation is only supported in WebGPU");
1507
- }
1508
- this.props = { ..._Computation.defaultProps, ...props };
1509
- props = this.props;
1510
- this.id = props.id || uid("model");
1511
- this.device = device;
1512
- Object.assign(this.userData, props.userData);
1513
- const moduleMap = Object.fromEntries(((_a = this.props.modules) == null ? void 0 : _a.map((module2) => [module2.name, module2])) || []);
1514
- this.shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap);
1515
- this.setShaderInputs(this.shaderInputs);
1516
- this.props.shaderLayout ||= device.getShaderLayout(this.props.source);
1517
- const platformInfo = getPlatformInfo(device);
1518
- const modules = (((_b = this.props.modules) == null ? void 0 : _b.length) > 0 ? this.props.modules : (_c = this.shaderInputs) == null ? void 0 : _c.getModules()) || [];
1519
- this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
1520
- this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
1521
- const { source: source3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleWGSLShader({
1522
- platformInfo,
1523
- ...this.props,
1524
- modules
1525
- });
1526
- this.source = source3;
1527
- this._getModuleUniforms = getUniforms2;
1528
- this.pipeline = this._updatePipeline();
1529
- if (props.bindings) {
1530
- this.setBindings(props.bindings);
1531
- }
1532
- Object.seal(this);
1533
- }
1534
- destroy() {
1535
- if (this._destroyed)
1536
- return;
1537
- this.pipelineFactory.release(this.pipeline);
1538
- this.shaderFactory.release(this.shader);
1539
- this._uniformStore.destroy();
1540
- this._destroyed = true;
1541
- }
1542
- // Draw call
1543
- predraw() {
1544
- this.updateShaderInputs();
1545
- }
1546
- dispatch(computePass, x, y, z) {
1547
- try {
1548
- this._logDrawCallStart();
1549
- this.pipeline = this._updatePipeline();
1550
- this.pipeline.setBindings(this.bindings);
1551
- computePass.setPipeline(this.pipeline);
1552
- computePass.setBindings([]);
1553
- computePass.dispatch(x, y, z);
1554
- } finally {
1555
- this._logDrawCallEnd();
1556
- }
1557
- }
1558
- // Update fixed fields (can trigger pipeline rebuild)
1559
- // Update dynamic fields
1560
- /**
1561
- * Updates the vertex count (used in draw calls)
1562
- * @note Any attributes with stepMode=vertex need to be at least this big
1563
- */
1564
- setVertexCount(vertexCount) {
1565
- }
1566
- /**
1567
- * Updates the instance count (used in draw calls)
1568
- * @note Any attributes with stepMode=instance need to be at least this big
1569
- */
1570
- setInstanceCount(instanceCount) {
1571
- }
1572
- setShaderInputs(shaderInputs) {
1573
- this.shaderInputs = shaderInputs;
1574
- this._uniformStore = new import_core9.UniformStore(this.shaderInputs.modules);
1575
- for (const moduleName of Object.keys(this.shaderInputs.modules)) {
1576
- const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
1577
- this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
1578
- }
1579
- }
1580
- /**
1581
- * Updates shader module settings (which results in uniforms being set)
1582
- */
1583
- setShaderModuleProps(props) {
1584
- const uniforms = this._getModuleUniforms(props);
1585
- const keys = Object.keys(uniforms).filter((k) => {
1586
- const uniform = uniforms[k];
1587
- return !(0, import_types2.isNumericArray)(uniform) && typeof uniform !== "number" && typeof uniform !== "boolean";
1588
- });
1589
- const bindings = {};
1590
- for (const k of keys) {
1591
- bindings[k] = uniforms[k];
1592
- delete uniforms[k];
1593
- }
1594
- }
1595
- updateShaderInputs() {
1596
- this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
1597
- }
1598
- /**
1599
- * Sets bindings (textures, samplers, uniform buffers)
1600
- */
1601
- setBindings(bindings) {
1602
- Object.assign(this.bindings, bindings);
1603
- }
1604
- _setPipelineNeedsUpdate(reason) {
1605
- this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
1606
- }
1607
- _updatePipeline() {
1608
- if (this._pipelineNeedsUpdate) {
1609
- let prevShader = null;
1610
- if (this.pipeline) {
1611
- import_core9.log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
1612
- prevShader = this.shader;
1613
- }
1614
- this._pipelineNeedsUpdate = false;
1615
- this.shader = this.shaderFactory.createShader({
1616
- id: `${this.id}-fragment`,
1617
- stage: "compute",
1618
- source: this.source,
1619
- debugShaders: this.props.debugShaders
1620
- });
1621
- this.pipeline = this.pipelineFactory.createComputePipeline({
1622
- ...this.props,
1623
- shader: this.shader
1624
- });
1625
- if (prevShader) {
1626
- this.shaderFactory.release(prevShader);
1627
- }
1628
- }
1629
- return this.pipeline;
1630
- }
1631
- /** Throttle draw call logging */
1632
- _lastLogTime = 0;
1633
- _logOpen = false;
1634
- _logDrawCallStart() {
1635
- const logDrawTimeout = import_core9.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
1636
- if (import_core9.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
1637
- return;
1638
- }
1639
- this._lastLogTime = Date.now();
1640
- this._logOpen = true;
1641
- import_core9.log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core9.log.level <= 2 })();
1642
- }
1643
- _logDrawCallEnd() {
1644
- if (this._logOpen) {
1645
- const uniformTable = this.shaderInputs.getDebugTable();
1646
- import_core9.log.table(LOG_DRAW_PRIORITY, uniformTable)();
1647
- import_core9.log.groupEnd(LOG_DRAW_PRIORITY)();
1648
- this._logOpen = false;
1649
- }
1650
- }
1651
- _drawCount = 0;
1652
- // TODO - fix typing of luma data types
1653
- _getBufferOrConstantValues(attribute, dataType) {
1654
- const TypedArrayConstructor = (0, import_core9.getTypedArrayConstructor)(dataType);
1655
- const typedArray = attribute instanceof import_core9.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
1656
- return typedArray.toString();
1657
- }
1658
- };
1659
- var Computation = _Computation;
1660
- __publicField(Computation, "defaultProps", {
1661
- ...import_core9.ComputePipeline.defaultProps,
1662
- id: "unnamed",
1663
- handle: void 0,
1664
- userData: {},
1665
- source: "",
1666
- modules: [],
1667
- defines: {},
1668
- bindings: void 0,
1669
- shaderInputs: void 0,
1670
- pipelineFactory: void 0,
1671
- shaderFactory: void 0,
1672
- shaderAssembler: import_shadertools2.ShaderAssembler.getDefaultShaderAssembler(),
1673
- debugShaders: void 0
1674
- });
1675
- function getPlatformInfo(device) {
1676
- return {
1677
- type: device.type,
1678
- shaderLanguage: device.info.shadingLanguage,
1679
- shaderLanguageVersion: device.info.shadingLanguageVersion,
1680
- gpu: device.info.gpu,
1681
- // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
1682
- features: device.features
1683
- };
1684
- }
1685
-
1686
- // dist/dynamic-texture/mipmaps.js
1687
- var RENDER_DIMENSIONS = [
1688
- "2d",
1689
- "2d-array",
1690
- "cube",
1691
- "cube-array"
1692
- ];
1693
- var WORKGROUP_SIZE = {
1694
- x: 4,
1695
- y: 4,
1696
- z: 4
1697
- };
1698
- function generateMipmap(device, texture) {
1699
- if (texture.mipLevels <= 1) {
1700
- return;
1701
- }
1702
- if (device.type !== "webgpu") {
1703
- throw new Error(`Cannot generate mipmaps on device type "${device.type}". Use generateMipmapsWebGL for WebGL devices.`);
1704
- }
1705
- if (texture.dimension === "3d") {
1706
- generateMipmaps3D(device, texture);
1707
- return;
1708
- }
1709
- if (RENDER_DIMENSIONS.includes(texture.dimension)) {
1710
- generateMipmapsRender(device, texture);
1711
- return;
1712
- }
1713
- throw new Error(`Cannot generate mipmaps for texture dimension "${texture.dimension}" with WebGPU.`);
1714
- }
1715
- function generateMipmapsRender(device, texture) {
1716
- validateFormatCapabilities(device, texture, ["render", "filter"], "render");
1717
- const colorAttachmentFormat = getColorAttachmentFormat(texture.format, "render", texture.dimension);
1718
- const viewDimension = texture.dimension;
1719
- const shader = getRenderMipmapWGSL(viewDimension);
1720
- const sampler = device.createSampler({ minFilter: "linear", magFilter: "linear" });
1721
- const uniformValues = new Uint32Array(1);
1722
- const uniformsBuffer = device.createBuffer({
1723
- byteLength: 16,
1724
- usage: import_core10.Buffer.UNIFORM | import_core10.Buffer.COPY_DST
1725
- });
1726
- const model = new Model(device, {
1727
- source: shader,
1728
- colorAttachmentFormats: [colorAttachmentFormat],
1729
- topology: "triangle-list",
1730
- vertexCount: 3,
1731
- shaderLayout: {
1732
- attributes: [],
1733
- bindings: [
1734
- { type: "sampler", name: "sourceSampler", group: 0, location: 0 },
1735
- {
1736
- type: "texture",
1737
- name: "sourceTexture",
1738
- group: 0,
1739
- location: 1,
1740
- viewDimension,
1741
- sampleType: "float"
1742
- },
1743
- { type: "uniform", name: "uniforms", group: 0, location: 2 }
1744
- ]
1745
- },
1746
- bindings: {
1747
- sourceSampler: sampler,
1748
- sourceTexture: texture,
1749
- uniforms: uniformsBuffer
1750
- }
1751
- });
1752
- let sourceWidth = texture.width;
1753
- let sourceHeight = texture.height;
1754
- const layerCount = texture.dimension === "2d" ? 1 : texture.depth;
1755
- try {
1756
- for (let baseMipLevel = 1; baseMipLevel < texture.mipLevels; ++baseMipLevel) {
1757
- validateFormatCapabilities(device, texture, ["render", "filter"], "render");
1758
- const sourceMipLevel = baseMipLevel - 1;
1759
- const destinationWidth = Math.max(1, sourceWidth >> 1);
1760
- const destinationHeight = Math.max(1, sourceHeight >> 1);
1761
- const sourceView = texture.createView({
1762
- dimension: viewDimension,
1763
- baseMipLevel: sourceMipLevel,
1764
- mipLevelCount: 1,
1765
- baseArrayLayer: 0,
1766
- arrayLayerCount: texture.depth
1767
- });
1768
- model.setBindings({ sourceTexture: sourceView });
1769
- for (let baseArrayLayer = 0; baseArrayLayer < layerCount; ++baseArrayLayer) {
1770
- uniformValues[0] = baseArrayLayer;
1771
- uniformsBuffer.write(uniformValues);
1772
- const destinationView = texture.createView({
1773
- dimension: "2d",
1774
- baseMipLevel,
1775
- mipLevelCount: 1,
1776
- baseArrayLayer,
1777
- arrayLayerCount: 1
1778
- });
1779
- const framebuffer = device.createFramebuffer({
1780
- colorAttachments: [destinationView]
1781
- });
1782
- const renderPass = device.beginRenderPass({
1783
- id: `mipmap-generation:${texture.format}:${baseMipLevel}:${baseArrayLayer}`,
1784
- framebuffer
1785
- });
1786
- renderPass.setParameters({
1787
- viewport: [0, 0, destinationWidth, destinationHeight, 0, 1],
1788
- scissorRect: [0, 0, destinationWidth, destinationHeight]
1789
- });
1790
- model.draw(renderPass);
1791
- renderPass.end();
1792
- device.submit();
1793
- destinationView.destroy();
1794
- framebuffer.destroy();
1795
- }
1796
- sourceView.destroy();
1797
- sourceWidth = destinationWidth;
1798
- sourceHeight = destinationHeight;
1799
- }
1800
- } finally {
1801
- model.destroy();
1802
- sampler.destroy();
1803
- uniformsBuffer.destroy();
1804
- }
1805
- }
1806
- function getColorAttachmentFormat(format, path, dimension) {
1807
- if (import_core10.textureFormatDecoder.isColor(format)) {
1808
- return format;
1809
- }
1810
- 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.`);
1811
- }
1812
- function generateMipmaps3D(device, texture) {
1813
- validateFormatCapabilities(device, texture, ["filter", "store"], "compute");
1814
- const format = getColorAttachmentFormat(texture.format, "compute", texture.dimension);
1815
- const shaderSource = get3DComputeMipmapWGSL(format);
1816
- const uniformsBuffer = device.createBuffer({
1817
- byteLength: 32,
1818
- usage: import_core10.Buffer.UNIFORM | import_core10.Buffer.COPY_DST
1819
- });
1820
- const uniformValues = new Uint32Array(8);
1821
- let sourceWidth = texture.width;
1822
- let sourceHeight = texture.height;
1823
- let sourceDepth = texture.depth;
1824
- try {
1825
- for (let destinationMipLevel = 1; destinationMipLevel < texture.mipLevels; ++destinationMipLevel) {
1826
- validateFormatCapabilities(device, texture, ["filter", "store"], "compute");
1827
- const destinationWidth = Math.max(1, sourceWidth >> 1);
1828
- const destinationHeight = Math.max(1, sourceHeight >> 1);
1829
- const destinationDepth = Math.max(1, sourceDepth >> 1);
1830
- uniformValues[0] = sourceWidth;
1831
- uniformValues[1] = sourceHeight;
1832
- uniformValues[2] = sourceDepth;
1833
- uniformValues[3] = destinationWidth;
1834
- uniformValues[4] = destinationHeight;
1835
- uniformValues[5] = destinationDepth;
1836
- uniformValues[6] = 0;
1837
- uniformsBuffer.write(uniformValues);
1838
- const sourceView = texture.createView({
1839
- dimension: "3d",
1840
- baseMipLevel: destinationMipLevel - 1,
1841
- mipLevelCount: 1,
1842
- baseArrayLayer: 0,
1843
- arrayLayerCount: 1
1844
- });
1845
- const destinationView = texture.createView({
1846
- dimension: "3d",
1847
- baseMipLevel: destinationMipLevel,
1848
- mipLevelCount: 1,
1849
- baseArrayLayer: 0,
1850
- arrayLayerCount: 1
1851
- });
1852
- const computation = new Computation(device, {
1853
- source: shaderSource,
1854
- shaderLayout: {
1855
- bindings: [
1856
- {
1857
- type: "texture",
1858
- name: "sourceTexture",
1859
- group: 0,
1860
- location: 0,
1861
- viewDimension: "3d",
1862
- sampleType: "float"
1863
- },
1864
- {
1865
- type: "storage",
1866
- name: "destinationTexture",
1867
- group: 0,
1868
- location: 1,
1869
- format,
1870
- viewDimension: "3d",
1871
- access: "write-only"
1872
- },
1873
- { type: "uniform", name: "uniforms", group: 0, location: 2 }
1874
- ]
1875
- },
1876
- bindings: {
1877
- sourceTexture: sourceView,
1878
- destinationTexture: destinationView,
1879
- uniforms: uniformsBuffer
1880
- }
1881
- });
1882
- const workgroupsX = Math.ceil(destinationWidth / WORKGROUP_SIZE.x);
1883
- const workgroupsY = Math.ceil(destinationHeight / WORKGROUP_SIZE.y);
1884
- const workgroupsZ = Math.ceil(destinationDepth / WORKGROUP_SIZE.z);
1885
- const computePass = device.beginComputePass({});
1886
- computation.dispatch(computePass, workgroupsX, workgroupsY, workgroupsZ);
1887
- computePass.end();
1888
- device.submit();
1889
- computation.destroy();
1890
- sourceView.destroy();
1891
- destinationView.destroy();
1892
- sourceWidth = destinationWidth;
1893
- sourceHeight = destinationHeight;
1894
- sourceDepth = destinationDepth;
1895
- }
1896
- } finally {
1897
- uniformsBuffer.destroy();
1898
- }
1899
- }
1900
- function validateFormatCapabilities(device, texture, requiredCapabilities, path) {
1901
- const { format, dimension } = texture;
1902
- const capabilities = device.getTextureFormatCapabilities(format);
1903
- const missingCapabilities = requiredCapabilities.filter((capability) => !capabilities[capability]);
1904
- if (missingCapabilities.length > 0) {
1905
- const required = requiredCapabilities.join(" + ");
1906
- const actual = requiredCapabilities.map((capability) => `${capability}=${capabilities[capability]}`).join(", ");
1907
- throw new Error(`Cannot run ${path} mipmap generation for ${dimension} texture with format "${format}". Required capabilities: ${required}. Actual capabilities: ${actual}.`);
1908
- }
1909
- }
1910
- function getSourceTextureType(dimension) {
1911
- switch (dimension) {
1912
- case "2d":
1913
- return "texture_2d<f32>";
1914
- case "2d-array":
1915
- return "texture_2d_array<f32>";
1916
- case "cube":
1917
- return "texture_cube<f32>";
1918
- case "cube-array":
1919
- return "texture_cube_array<f32>";
1920
- default:
1921
- throw new Error(`Unsupported render dimension "${dimension}" for mipmap generation.`);
1922
- }
1923
- }
1924
- function getRenderMipmapWGSL(dimension) {
1925
- const sourceSnippet = getRenderMipmapSampleSnippet(dimension);
1926
- return `
1927
- struct MipmapUniforms {
1928
- sourceLayer: u32,
1929
- };
1930
-
1931
- fn _touchUniform(uniforms: MipmapUniforms) {
1932
- let unusedSourceLayer = uniforms.sourceLayer;
1933
- }
1934
-
1935
- const faceMat = array(
1936
- mat3x3f(
1937
- 0.0, 0.0, -2.0,
1938
- 0.0, -2.0, 0.0,
1939
- 1.0, 1.0, 1.0
1940
- ), // pos-x
1941
- mat3x3f(
1942
- 0.0, 0.0, 2.0,
1943
- 0.0, -2.0, 0.0,
1944
- -1.0, 1.0, -1.0
1945
- ), // neg-x
1946
- mat3x3f(
1947
- 2.0, 0.0, 0.0,
1948
- 0.0, 0.0, 2.0,
1949
- -1.0, 1.0, -1.0
1950
- ), // pos-y
1951
- mat3x3f(
1952
- 2.0, 0.0, 0.0,
1953
- 0.0, 0.0, -2.0,
1954
- -1.0, -1.0, 1.0
1955
- ), // neg-y
1956
- mat3x3f(
1957
- 2.0, 0.0, 0.0,
1958
- 0.0, -2.0, 0.0,
1959
- -1.0, 1.0, 1.0
1960
- ), // pos-z
1961
- mat3x3f(
1962
- -2.0, 0.0, 0.0,
1963
- 0.0, -2.0, 0.0,
1964
- 1.0, 1.0, -1.0
1965
- ) // neg-z
1966
- );
1967
-
1968
- struct FragmentInputs {
1969
- @builtin(position) position: vec4f,
1970
- @location(0) texcoord: vec2f
1971
- };
1972
-
1973
- struct VertexOutput {
1974
- @builtin(position) position: vec4f,
1975
- @location(0) texcoord: vec2f
1976
- };
1977
-
1978
- @group(0) @binding(0) var sourceSampler: sampler;
1979
- @group(0) @binding(1) var sourceTexture: ${getSourceTextureType(dimension)};
1980
- @group(0) @binding(2) var<uniform> uniforms: MipmapUniforms;
1981
-
1982
- @vertex
1983
- fn vertexMain(
1984
- @builtin(vertex_index) vertexIndex: u32
1985
- ) -> VertexOutput {
1986
- const positions = array(
1987
- vec2f(-1.0, -1.0),
1988
- vec2f(-1.0, 3.0),
1989
- vec2f( 3.0, -1.0)
1990
- );
1991
-
1992
- let xy = positions[vertexIndex];
1993
- return VertexOutput(
1994
- vec4f(xy, 0.0, 1.0),
1995
- xy * vec2f(0.5, -0.5) + vec2f(0.5)
1996
- );
1997
- }
1998
-
1999
- @fragment
2000
- fn fragmentMain(fsInput: VertexOutput) -> @location(0) vec4f {
2001
- _touchUniform(uniforms);
2002
- return ${sourceSnippet};
2003
- }
2004
- `;
2005
- }
2006
- function getRenderMipmapSampleSnippet(dimension) {
2007
- const layer = "uniforms.sourceLayer";
2008
- switch (dimension) {
2009
- case "2d":
2010
- return "textureSampleLevel(sourceTexture, sourceSampler, fsInput.texcoord, 0.0)";
2011
- case "2d-array":
2012
- return `textureSampleLevel(sourceTexture, sourceSampler, fsInput.texcoord, i32(${layer}), 0.0)`;
2013
- case "cube":
2014
- return `textureSampleLevel(sourceTexture, sourceSampler, faceMat[i32(${layer})] * vec3f(fract(fsInput.texcoord), 1.0), 0.0)`;
2015
- case "cube-array":
2016
- return `textureSampleLevel(sourceTexture, sourceSampler, faceMat[i32(${layer} % 6u)] * vec3f(fract(fsInput.texcoord), 1.0), i32(${layer} / 6u), 0.0)`;
2017
- default:
2018
- throw new Error(`Unsupported render dimension "${dimension}" for mipmap generation.`);
2019
- }
2020
- }
2021
- function get3DComputeMipmapWGSL(format) {
2022
- return `
2023
- struct MipmapUniforms {
2024
- sourceWidth: u32,
2025
- sourceHeight: u32,
2026
- sourceDepth: u32,
2027
- destinationWidth: u32,
2028
- destinationHeight: u32,
2029
- destinationDepth: u32,
2030
- padding: u32,
2031
- };
2032
-
2033
- @group(0) @binding(0) var sourceTexture: texture_3d<f32>;
2034
- @group(0) @binding(1) var destinationTexture: texture_storage_3d<${format}, write>;
2035
- @group(0) @binding(2) var<uniform> uniforms: MipmapUniforms;
2036
-
2037
- @compute @workgroup_size(${WORKGROUP_SIZE.x}, ${WORKGROUP_SIZE.y}, ${WORKGROUP_SIZE.z})
2038
- fn main(@builtin(global_invocation_id) id: vec3<u32>) {
2039
- if (
2040
- id.x >= uniforms.destinationWidth ||
2041
- id.y >= uniforms.destinationHeight ||
2042
- id.z >= uniforms.destinationDepth
2043
- ) {
2044
- return;
2045
- }
2046
-
2047
- let sourceBase = id * 2u;
2048
- let sourceX0 = min(sourceBase.x, uniforms.sourceWidth - 1u);
2049
- let sourceY0 = min(sourceBase.y, uniforms.sourceHeight - 1u);
2050
- let sourceZ0 = min(sourceBase.z, uniforms.sourceDepth - 1u);
2051
-
2052
- let sourceX1 = min(sourceBase.x + 1u, uniforms.sourceWidth - 1u);
2053
- let sourceY1 = min(sourceBase.y + 1u, uniforms.sourceHeight - 1u);
2054
- let sourceZ1 = min(sourceBase.z + 1u, uniforms.sourceDepth - 1u);
2055
-
2056
- var sum = textureLoad(
2057
- sourceTexture,
2058
- vec3<i32>(i32(sourceX0), i32(sourceY0), i32(sourceZ0)),
2059
- 0
2060
- );
2061
- sum += textureLoad(
2062
- sourceTexture,
2063
- vec3<i32>(i32(sourceX1), i32(sourceY0), i32(sourceZ0)),
2064
- 0
2065
- );
2066
- sum += textureLoad(
2067
- sourceTexture,
2068
- vec3<i32>(i32(sourceX0), i32(sourceY1), i32(sourceZ0)),
2069
- 0
2070
- );
2071
- sum += textureLoad(
2072
- sourceTexture,
2073
- vec3<i32>(i32(sourceX1), i32(sourceY1), i32(sourceZ0)),
2074
- 0
2075
- );
2076
- sum += textureLoad(
2077
- sourceTexture,
2078
- vec3<i32>(i32(sourceX0), i32(sourceY0), i32(sourceZ1)),
2079
- 0
2080
- );
2081
- sum += textureLoad(
2082
- sourceTexture,
2083
- vec3<i32>(i32(sourceX1), i32(sourceY0), i32(sourceZ1)),
2084
- 0
2085
- );
2086
- sum += textureLoad(
2087
- sourceTexture,
2088
- vec3<i32>(i32(sourceX0), i32(sourceY1), i32(sourceZ1)),
2089
- 0
2090
- );
2091
- sum += textureLoad(
2092
- sourceTexture,
2093
- vec3<i32>(i32(sourceX1), i32(sourceY1), i32(sourceZ1)),
2094
- 0
2095
- );
2096
-
2097
- textureStore(
2098
- destinationTexture,
2099
- vec3<i32>(i32(id.x), i32(id.y), i32(id.z)),
2100
- vec4<f32>(sum.xyz / 8.0, sum.w / 8.0)
2101
- );
2102
- }
2103
- `;
2104
- }
2105
-
2106
1575
  // dist/dynamic-texture/dynamic-texture.js
2107
1576
  var _DynamicTexture = class {
2108
1577
  device;
@@ -2159,6 +1628,9 @@ var _DynamicTexture = class {
2159
1628
  try {
2160
1629
  const propsWithSyncData = await this._loadAllData(originalPropsWithAsyncData);
2161
1630
  this._checkNotDestroyed();
1631
+ const subresources = propsWithSyncData.data ? getTextureSubresources(propsWithSyncData) : [];
1632
+ const userProvidedFormat = "format" in originalPropsWithAsyncData && originalPropsWithAsyncData.format !== void 0;
1633
+ const userProvidedUsage = "usage" in originalPropsWithAsyncData && originalPropsWithAsyncData.usage !== void 0;
2162
1634
  const deduceSize = () => {
2163
1635
  if (this.props.width && this.props.height) {
2164
1636
  return { width: this.props.width, height: this.props.height };
@@ -2173,54 +1645,44 @@ var _DynamicTexture = class {
2173
1645
  if (!size || size.width <= 0 || size.height <= 0) {
2174
1646
  throw new Error(`${this} size could not be determined or was zero`);
2175
1647
  }
1648
+ const textureData = analyzeTextureSubresources(this.device, subresources, size, {
1649
+ format: userProvidedFormat ? originalPropsWithAsyncData.format : void 0
1650
+ });
1651
+ const resolvedFormat = textureData.format ?? this.props.format;
2176
1652
  const baseTextureProps = {
2177
1653
  ...this.props,
2178
1654
  ...size,
1655
+ format: resolvedFormat,
2179
1656
  mipLevels: 1,
2180
1657
  // temporary; updated below
2181
1658
  data: void 0
2182
1659
  };
2183
- if (this.device.type === "webgpu" && this.props.mipmaps) {
2184
- const requiredUsage = this.props.dimension === "3d" ? import_core11.Texture.SAMPLE | import_core11.Texture.STORAGE | import_core11.Texture.COPY_DST | import_core11.Texture.COPY_SRC : import_core11.Texture.SAMPLE | import_core11.Texture.RENDER | import_core11.Texture.COPY_DST | import_core11.Texture.COPY_SRC;
1660
+ if (this.device.isTextureFormatCompressed(resolvedFormat) && !userProvidedUsage) {
1661
+ baseTextureProps.usage = import_core9.Texture.SAMPLE | import_core9.Texture.COPY_DST;
1662
+ }
1663
+ const shouldGenerateMipmaps = this.props.mipmaps && !textureData.hasExplicitMipChain && !this.device.isTextureFormatCompressed(resolvedFormat);
1664
+ if (this.device.type === "webgpu" && shouldGenerateMipmaps) {
1665
+ const requiredUsage = this.props.dimension === "3d" ? import_core9.Texture.SAMPLE | import_core9.Texture.STORAGE | import_core9.Texture.COPY_DST | import_core9.Texture.COPY_SRC : import_core9.Texture.SAMPLE | import_core9.Texture.RENDER | import_core9.Texture.COPY_DST | import_core9.Texture.COPY_SRC;
2185
1666
  baseTextureProps.usage |= requiredUsage;
2186
1667
  }
2187
1668
  const maxMips = this.device.getMipLevelCount(baseTextureProps.width, baseTextureProps.height);
2188
- const desired = this.props.mipLevels === "auto" ? maxMips : Math.max(1, Math.min(maxMips, this.props.mipLevels ?? 1));
1669
+ const desired = textureData.hasExplicitMipChain ? textureData.mipLevels : this.props.mipLevels === "auto" ? maxMips : Math.max(1, Math.min(maxMips, this.props.mipLevels ?? 1));
2189
1670
  const finalTextureProps = { ...baseTextureProps, mipLevels: desired };
2190
1671
  this._texture = this.device.createTexture(finalTextureProps);
2191
1672
  this._sampler = this.texture.sampler;
2192
1673
  this._view = this.texture.view;
2193
- if (propsWithSyncData.data) {
2194
- switch (propsWithSyncData.dimension) {
2195
- case "1d":
2196
- this.setTexture1DData(propsWithSyncData.data);
2197
- break;
2198
- case "2d":
2199
- this.setTexture2DData(propsWithSyncData.data);
2200
- break;
2201
- case "3d":
2202
- this.setTexture3DData(propsWithSyncData.data);
2203
- break;
2204
- case "2d-array":
2205
- this.setTextureArrayData(propsWithSyncData.data);
2206
- break;
2207
- case "cube":
2208
- this.setTextureCubeData(propsWithSyncData.data);
2209
- break;
2210
- case "cube-array":
2211
- this.setTextureCubeArrayData(propsWithSyncData.data);
2212
- break;
2213
- default: {
2214
- throw new Error(`Unhandled dimension ${propsWithSyncData.dimension}`);
2215
- }
2216
- }
1674
+ if (textureData.subresources.length) {
1675
+ this._setTextureSubresources(textureData.subresources);
1676
+ }
1677
+ if (this.props.mipmaps && !textureData.hasExplicitMipChain && !shouldGenerateMipmaps) {
1678
+ import_core9.log.warn(`${this} skipping auto-generated mipmaps for compressed texture format`)();
2217
1679
  }
2218
- if (this.props.mipmaps) {
1680
+ if (shouldGenerateMipmaps) {
2219
1681
  this.generateMipmaps();
2220
1682
  }
2221
1683
  this.isReady = true;
2222
1684
  this.resolveReady(this.texture);
2223
- import_core11.log.info(0, `${this} created`)();
1685
+ import_core9.log.info(0, `${this} created`)();
2224
1686
  } catch (e) {
2225
1687
  const err = e instanceof Error ? e : new Error(String(e));
2226
1688
  this.rejectReady(err);
@@ -2240,15 +1702,15 @@ var _DynamicTexture = class {
2240
1702
  if (this.device.type === "webgl") {
2241
1703
  this.texture.generateMipmapsWebGL();
2242
1704
  } else if (this.device.type === "webgpu") {
2243
- generateMipmap(this.device, this.texture);
1705
+ this.device.generateMipmapsWebGPU(this.texture);
2244
1706
  } else {
2245
- import_core11.log.warn(`${this} mipmaps not supported on ${this.device.type}`);
1707
+ import_core9.log.warn(`${this} mipmaps not supported on ${this.device.type}`);
2246
1708
  }
2247
1709
  }
2248
1710
  /** Set sampler or create one from props */
2249
1711
  setSampler(sampler = {}) {
2250
1712
  this._checkReady();
2251
- const s = sampler instanceof import_core11.Sampler ? sampler : this.device.createSampler(sampler);
1713
+ const s = sampler instanceof import_core9.Sampler ? sampler : this.device.createSampler(sampler);
2252
1714
  this.texture.setSampler(s);
2253
1715
  this._sampler = s;
2254
1716
  }
@@ -2266,7 +1728,7 @@ var _DynamicTexture = class {
2266
1728
  this._sampler = this.texture.sampler;
2267
1729
  this._view = this.texture.view;
2268
1730
  prev.destroy();
2269
- import_core11.log.info(`${this} resized`);
1731
+ import_core9.log.info(`${this} resized`);
2270
1732
  return true;
2271
1733
  }
2272
1734
  /** Convert cube face label to texture slice index. Index can be used with `setTexture2DData()`. */
@@ -2340,8 +1802,11 @@ var _DynamicTexture = class {
2340
1802
  this.texture.copyExternalImage({ image, z, mipLevel, flipY });
2341
1803
  break;
2342
1804
  case "texture-data":
2343
- const { data } = subresource;
2344
- this.texture.writeData(getAlignedUploadData(this.texture, data), {
1805
+ const { data, textureFormat } = subresource;
1806
+ if (textureFormat && textureFormat !== this.texture.format) {
1807
+ throw new Error(`${this} mip level ${mipLevel} uses format "${textureFormat}" but texture format is "${this.texture.format}"`);
1808
+ }
1809
+ this.texture.writeData(data.data, {
2345
1810
  x: 0,
2346
1811
  y: 0,
2347
1812
  z,
@@ -2365,38 +1830,149 @@ var _DynamicTexture = class {
2365
1830
  }
2366
1831
  _checkNotDestroyed() {
2367
1832
  if (this.destroyed) {
2368
- import_core11.log.warn(`${this} already destroyed`);
1833
+ import_core9.log.warn(`${this} already destroyed`);
2369
1834
  }
2370
1835
  }
2371
1836
  _checkReady() {
2372
1837
  if (!this.isReady) {
2373
- import_core11.log.warn(`${this} Cannot perform this operation before ready`);
1838
+ import_core9.log.warn(`${this} Cannot perform this operation before ready`);
2374
1839
  }
2375
1840
  }
2376
1841
  };
2377
1842
  var DynamicTexture = _DynamicTexture;
2378
1843
  __publicField(DynamicTexture, "defaultProps", {
2379
- ...import_core11.Texture.defaultProps,
1844
+ ...import_core9.Texture.defaultProps,
2380
1845
  dimension: "2d",
2381
1846
  data: null,
2382
1847
  mipmaps: false
2383
1848
  });
2384
- function getAlignedUploadData(texture, data) {
2385
- const { width, height, data: uploadData } = data;
2386
- const { bytesPerPixel } = texture.device.getTextureFormatInfo(texture.format);
2387
- const bytesPerRow = width * bytesPerPixel;
2388
- const alignedBytesPerRow = Math.ceil(bytesPerRow / texture.byteAlignment) * texture.byteAlignment;
2389
- if (alignedBytesPerRow === bytesPerRow) {
2390
- return uploadData;
2391
- }
2392
- const sourceBytes = new Uint8Array(uploadData.buffer, uploadData.byteOffset, uploadData.byteLength);
2393
- const paddedBytes = new Uint8Array(alignedBytesPerRow * height);
2394
- for (let row = 0; row < height; row++) {
2395
- const sourceOffset = row * bytesPerRow;
2396
- const destinationOffset = row * alignedBytesPerRow;
2397
- paddedBytes.set(sourceBytes.subarray(sourceOffset, sourceOffset + bytesPerRow), destinationOffset);
2398
- }
2399
- return paddedBytes;
1849
+ function getTextureSubresources(props) {
1850
+ if (!props.data) {
1851
+ return [];
1852
+ }
1853
+ switch (props.dimension) {
1854
+ case "1d":
1855
+ return getTexture1DSubresources(props.data);
1856
+ case "2d":
1857
+ return getTexture2DSubresources(0, props.data);
1858
+ case "3d":
1859
+ return getTexture3DSubresources(props.data);
1860
+ case "2d-array":
1861
+ return getTextureArraySubresources(props.data);
1862
+ case "cube":
1863
+ return getTextureCubeSubresources(props.data);
1864
+ case "cube-array":
1865
+ return getTextureCubeArraySubresources(props.data);
1866
+ default:
1867
+ throw new Error(`Unhandled dimension ${props.dimension}`);
1868
+ }
1869
+ }
1870
+ function analyzeTextureSubresources(device, subresources, size, options) {
1871
+ if (subresources.length === 0) {
1872
+ return {
1873
+ subresources,
1874
+ mipLevels: 1,
1875
+ format: options.format,
1876
+ hasExplicitMipChain: false
1877
+ };
1878
+ }
1879
+ const groupedSubresources = /* @__PURE__ */ new Map();
1880
+ for (const subresource of subresources) {
1881
+ const group = groupedSubresources.get(subresource.z) ?? [];
1882
+ group.push(subresource);
1883
+ groupedSubresources.set(subresource.z, group);
1884
+ }
1885
+ const hasExplicitMipChain = subresources.some((subresource) => subresource.mipLevel > 0);
1886
+ let resolvedFormat = options.format;
1887
+ let resolvedMipLevels = Number.POSITIVE_INFINITY;
1888
+ const validSubresources = [];
1889
+ for (const [z, sliceSubresources] of groupedSubresources) {
1890
+ const sortedSubresources = [...sliceSubresources].sort((left, right) => left.mipLevel - right.mipLevel);
1891
+ const baseLevel = sortedSubresources[0];
1892
+ if (!baseLevel || baseLevel.mipLevel !== 0) {
1893
+ throw new Error(`DynamicTexture: slice ${z} is missing mip level 0`);
1894
+ }
1895
+ const baseSize = getTextureSubresourceSize(device, baseLevel);
1896
+ if (baseSize.width !== size.width || baseSize.height !== size.height) {
1897
+ throw new Error(`DynamicTexture: slice ${z} base level dimensions ${baseSize.width}x${baseSize.height} do not match expected ${size.width}x${size.height}`);
1898
+ }
1899
+ const baseFormat = getTextureSubresourceFormat(baseLevel);
1900
+ if (baseFormat) {
1901
+ if (resolvedFormat && resolvedFormat !== baseFormat) {
1902
+ throw new Error(`DynamicTexture: slice ${z} base level format "${baseFormat}" does not match texture format "${resolvedFormat}"`);
1903
+ }
1904
+ resolvedFormat = baseFormat;
1905
+ }
1906
+ const mipLevelLimit = resolvedFormat && device.isTextureFormatCompressed(resolvedFormat) ? (
1907
+ // Block-compressed formats cannot have mips smaller than a single compression block.
1908
+ getMaxCompressedMipLevels(device, baseSize.width, baseSize.height, resolvedFormat)
1909
+ ) : device.getMipLevelCount(baseSize.width, baseSize.height);
1910
+ let validMipLevelsForSlice = 0;
1911
+ for (let expectedMipLevel = 0; expectedMipLevel < sortedSubresources.length; expectedMipLevel++) {
1912
+ const subresource = sortedSubresources[expectedMipLevel];
1913
+ if (!subresource || subresource.mipLevel !== expectedMipLevel) {
1914
+ break;
1915
+ }
1916
+ if (expectedMipLevel >= mipLevelLimit) {
1917
+ break;
1918
+ }
1919
+ const subresourceSize = getTextureSubresourceSize(device, subresource);
1920
+ const expectedWidth = Math.max(1, baseSize.width >> expectedMipLevel);
1921
+ const expectedHeight = Math.max(1, baseSize.height >> expectedMipLevel);
1922
+ if (subresourceSize.width !== expectedWidth || subresourceSize.height !== expectedHeight) {
1923
+ break;
1924
+ }
1925
+ const subresourceFormat = getTextureSubresourceFormat(subresource);
1926
+ if (subresourceFormat) {
1927
+ if (!resolvedFormat) {
1928
+ resolvedFormat = subresourceFormat;
1929
+ }
1930
+ if (subresourceFormat !== resolvedFormat) {
1931
+ break;
1932
+ }
1933
+ }
1934
+ validMipLevelsForSlice++;
1935
+ validSubresources.push(subresource);
1936
+ }
1937
+ resolvedMipLevels = Math.min(resolvedMipLevels, validMipLevelsForSlice);
1938
+ }
1939
+ const mipLevels = Number.isFinite(resolvedMipLevels) ? Math.max(1, resolvedMipLevels) : 1;
1940
+ return {
1941
+ // Keep every slice trimmed to the same mip count so the texture shape stays internally consistent.
1942
+ subresources: validSubresources.filter((subresource) => subresource.mipLevel < mipLevels),
1943
+ mipLevels,
1944
+ format: resolvedFormat,
1945
+ hasExplicitMipChain
1946
+ };
1947
+ }
1948
+ function getTextureSubresourceFormat(subresource) {
1949
+ if (subresource.type !== "texture-data") {
1950
+ return void 0;
1951
+ }
1952
+ return subresource.textureFormat ?? resolveTextureImageFormat(subresource.data);
1953
+ }
1954
+ function getTextureSubresourceSize(device, subresource) {
1955
+ switch (subresource.type) {
1956
+ case "external-image":
1957
+ return device.getExternalImageSize(subresource.image);
1958
+ case "texture-data":
1959
+ return { width: subresource.data.width, height: subresource.data.height };
1960
+ default:
1961
+ throw new Error("Unsupported texture subresource");
1962
+ }
1963
+ }
1964
+ function getMaxCompressedMipLevels(device, baseWidth, baseHeight, format) {
1965
+ const { blockWidth = 1, blockHeight = 1 } = device.getTextureFormatInfo(format);
1966
+ let mipLevels = 1;
1967
+ for (let mipLevel = 1; ; mipLevel++) {
1968
+ const width = Math.max(1, baseWidth >> mipLevel);
1969
+ const height = Math.max(1, baseHeight >> mipLevel);
1970
+ if (width < blockWidth || height < blockHeight) {
1971
+ break;
1972
+ }
1973
+ mipLevels++;
1974
+ }
1975
+ return mipLevels;
2400
1976
  }
2401
1977
  async function awaitAllPromises(x) {
2402
1978
  x = await x;
@@ -2417,8 +1993,8 @@ async function awaitAllPromises(x) {
2417
1993
  }
2418
1994
 
2419
1995
  // dist/model/model.js
2420
- var LOG_DRAW_PRIORITY2 = 2;
2421
- var LOG_DRAW_TIMEOUT2 = 1e4;
1996
+ var LOG_DRAW_PRIORITY = 2;
1997
+ var LOG_DRAW_TIMEOUT = 1e4;
2422
1998
  var _Model = class {
2423
1999
  /** Device that created this model */
2424
2000
  device;
@@ -2500,7 +2076,7 @@ var _Model = class {
2500
2076
  const moduleMap = Object.fromEntries(((_a = this.props.modules) == null ? void 0 : _a.map((module2) => [module2.name, module2])) || []);
2501
2077
  const shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap, { disableWarnings: this.props.disableWarnings });
2502
2078
  this.setShaderInputs(shaderInputs);
2503
- const platformInfo = getPlatformInfo2(device);
2079
+ const platformInfo = getPlatformInfo(device);
2504
2080
  const modules = (
2505
2081
  // @ts-ignore shaderInputs is assigned in setShaderInputs above.
2506
2082
  (((_b = this.props.modules) == null ? void 0 : _b.length) > 0 ? this.props.modules : (_c = this.shaderInputs) == null ? void 0 : _c.getModules()) || []
@@ -2573,7 +2149,7 @@ var _Model = class {
2573
2149
  if (!this._destroyed) {
2574
2150
  this.pipelineFactory.release(this.pipeline);
2575
2151
  this.shaderFactory.release(this.pipeline.vs);
2576
- if (this.pipeline.fs) {
2152
+ if (this.pipeline.fs && this.pipeline.fs !== this.pipeline.vs) {
2577
2153
  this.shaderFactory.release(this.pipeline.fs);
2578
2154
  }
2579
2155
  this._uniformStore.destroy();
@@ -2608,7 +2184,7 @@ var _Model = class {
2608
2184
  draw(renderPass) {
2609
2185
  const loadingBinding = this._areBindingsLoading();
2610
2186
  if (loadingBinding) {
2611
- import_core12.log.info(LOG_DRAW_PRIORITY2, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
2187
+ import_core10.log.info(LOG_DRAW_PRIORITY, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
2612
2188
  return false;
2613
2189
  }
2614
2190
  try {
@@ -2623,9 +2199,6 @@ var _Model = class {
2623
2199
  this._logDrawCallStart();
2624
2200
  this.pipeline = this._updatePipeline();
2625
2201
  const syncBindings = this._getBindings();
2626
- this.pipeline.setBindings(syncBindings, {
2627
- disableWarnings: this.props.disableWarnings
2628
- });
2629
2202
  const { indexBuffer } = this.vertexArray;
2630
2203
  const indexCount = indexBuffer ? indexBuffer.byteLength / (indexBuffer.indexType === "uint32" ? 4 : 2) : void 0;
2631
2204
  drawSuccess = this.pipeline.draw({
@@ -2636,6 +2209,11 @@ var _Model = class {
2636
2209
  instanceCount: this.instanceCount,
2637
2210
  indexCount,
2638
2211
  transformFeedback: this.transformFeedback || void 0,
2212
+ // Pipelines may be shared across models when caching is enabled, so bindings
2213
+ // and WebGL uniforms must be supplied on every draw instead of being stored
2214
+ // on the pipeline instance.
2215
+ bindings: syncBindings,
2216
+ uniforms: this.props.uniforms,
2639
2217
  // WebGL shares underlying cached pipelines even for models that have different parameters and topology,
2640
2218
  // so we must provide our unique parameters to each draw
2641
2219
  // (In WebGPU most parameters are encoded in the pipeline and cannot be changed per draw call)
@@ -2736,7 +2314,7 @@ var _Model = class {
2736
2314
  /** Set the shader inputs */
2737
2315
  setShaderInputs(shaderInputs) {
2738
2316
  this.shaderInputs = shaderInputs;
2739
- this._uniformStore = new import_core12.UniformStore(this.shaderInputs.modules);
2317
+ this._uniformStore = new import_core10.UniformStore(this.shaderInputs.modules);
2740
2318
  for (const [moduleName, module2] of Object.entries(this.shaderInputs.modules)) {
2741
2319
  if (shaderModuleHasUniforms(module2)) {
2742
2320
  const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
@@ -2780,7 +2358,7 @@ var _Model = class {
2780
2358
  setAttributes(buffers, options) {
2781
2359
  const disableWarnings = (options == null ? void 0 : options.disableWarnings) ?? this.props.disableWarnings;
2782
2360
  if (buffers["indices"]) {
2783
- import_core12.log.warn(`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`)();
2361
+ import_core10.log.warn(`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`)();
2784
2362
  }
2785
2363
  this.bufferLayout = sortedBufferLayoutByShaderSourceLocations(this.pipeline.shaderLayout, this.bufferLayout);
2786
2364
  const bufferLayoutHelper = new BufferLayoutHelper(this.bufferLayout);
@@ -2788,7 +2366,7 @@ var _Model = class {
2788
2366
  const bufferLayout = bufferLayoutHelper.getBufferLayout(bufferName);
2789
2367
  if (!bufferLayout) {
2790
2368
  if (!disableWarnings) {
2791
- import_core12.log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
2369
+ import_core10.log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
2792
2370
  }
2793
2371
  continue;
2794
2372
  }
@@ -2803,7 +2381,7 @@ var _Model = class {
2803
2381
  }
2804
2382
  }
2805
2383
  if (!set && !disableWarnings) {
2806
- import_core12.log.warn(`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`)();
2384
+ import_core10.log.warn(`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`)();
2807
2385
  }
2808
2386
  }
2809
2387
  this.setNeedsRedraw("attributes");
@@ -2822,7 +2400,7 @@ var _Model = class {
2822
2400
  if (attributeInfo) {
2823
2401
  this.vertexArray.setConstantWebGL(attributeInfo.location, value);
2824
2402
  } else if (!((options == null ? void 0 : options.disableWarnings) ?? this.props.disableWarnings)) {
2825
- import_core12.log.warn(`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`)();
2403
+ import_core10.log.warn(`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`)();
2826
2404
  }
2827
2405
  }
2828
2406
  this.setNeedsRedraw("constants");
@@ -2855,16 +2433,16 @@ var _Model = class {
2855
2433
  _getBindingsUpdateTimestamp() {
2856
2434
  let timestamp = 0;
2857
2435
  for (const binding of Object.values(this.bindings)) {
2858
- if (binding instanceof import_core12.TextureView) {
2436
+ if (binding instanceof import_core10.TextureView) {
2859
2437
  timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
2860
- } else if (binding instanceof import_core12.Buffer || binding instanceof import_core12.Texture) {
2438
+ } else if (binding instanceof import_core10.Buffer || binding instanceof import_core10.Texture) {
2861
2439
  timestamp = Math.max(timestamp, binding.updateTimestamp);
2862
2440
  } else if (binding instanceof DynamicTexture) {
2863
2441
  timestamp = binding.texture ? Math.max(timestamp, binding.texture.updateTimestamp) : (
2864
2442
  // The texture will become available in the future
2865
2443
  Infinity
2866
2444
  );
2867
- } else if (!(binding instanceof import_core12.Sampler)) {
2445
+ } else if (!(binding instanceof import_core10.Sampler)) {
2868
2446
  timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
2869
2447
  }
2870
2448
  }
@@ -2899,7 +2477,7 @@ var _Model = class {
2899
2477
  let prevShaderVs = null;
2900
2478
  let prevShaderFs = null;
2901
2479
  if (this.pipeline) {
2902
- import_core12.log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
2480
+ import_core10.log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
2903
2481
  prevShaderVs = this.pipeline.vs;
2904
2482
  prevShaderFs = this.pipeline.fs;
2905
2483
  }
@@ -2932,11 +2510,12 @@ var _Model = class {
2932
2510
  vs: vs3,
2933
2511
  fs: fs3
2934
2512
  });
2935
- this._attributeInfos = (0, import_core12.getAttributeInfosFromLayouts)(this.pipeline.shaderLayout, this.bufferLayout);
2513
+ this._attributeInfos = (0, import_core10.getAttributeInfosFromLayouts)(this.pipeline.shaderLayout, this.bufferLayout);
2936
2514
  if (prevShaderVs)
2937
2515
  this.shaderFactory.release(prevShaderVs);
2938
- if (prevShaderFs)
2516
+ if (prevShaderFs && prevShaderFs !== prevShaderVs) {
2939
2517
  this.shaderFactory.release(prevShaderFs);
2518
+ }
2940
2519
  }
2941
2520
  return this.pipeline;
2942
2521
  }
@@ -2944,24 +2523,24 @@ var _Model = class {
2944
2523
  _lastLogTime = 0;
2945
2524
  _logOpen = false;
2946
2525
  _logDrawCallStart() {
2947
- const logDrawTimeout = import_core12.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT2;
2948
- if (import_core12.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
2526
+ const logDrawTimeout = import_core10.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
2527
+ if (import_core10.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
2949
2528
  return;
2950
2529
  }
2951
2530
  this._lastLogTime = Date.now();
2952
2531
  this._logOpen = true;
2953
- import_core12.log.group(LOG_DRAW_PRIORITY2, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core12.log.level <= 2 })();
2532
+ import_core10.log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core10.log.level <= 2 })();
2954
2533
  }
2955
2534
  _logDrawCallEnd() {
2956
2535
  if (this._logOpen) {
2957
2536
  const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.shaderLayout, this.id);
2958
- import_core12.log.table(LOG_DRAW_PRIORITY2, shaderLayoutTable)();
2537
+ import_core10.log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
2959
2538
  const uniformTable = this.shaderInputs.getDebugTable();
2960
- import_core12.log.table(LOG_DRAW_PRIORITY2, uniformTable)();
2539
+ import_core10.log.table(LOG_DRAW_PRIORITY, uniformTable)();
2961
2540
  const attributeTable = this._getAttributeDebugTable();
2962
- import_core12.log.table(LOG_DRAW_PRIORITY2, this._attributeInfos)();
2963
- import_core12.log.table(LOG_DRAW_PRIORITY2, attributeTable)();
2964
- import_core12.log.groupEnd(LOG_DRAW_PRIORITY2)();
2541
+ import_core10.log.table(LOG_DRAW_PRIORITY, this._attributeInfos)();
2542
+ import_core10.log.table(LOG_DRAW_PRIORITY, attributeTable)();
2543
+ import_core10.log.groupEnd(LOG_DRAW_PRIORITY)();
2965
2544
  this._logOpen = false;
2966
2545
  }
2967
2546
  }
@@ -3000,14 +2579,14 @@ var _Model = class {
3000
2579
  }
3001
2580
  // TODO - fix typing of luma data types
3002
2581
  _getBufferOrConstantValues(attribute, dataType) {
3003
- const TypedArrayConstructor = (0, import_core12.getTypedArrayConstructor)(dataType);
3004
- const typedArray = attribute instanceof import_core12.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
2582
+ const TypedArrayConstructor = (0, import_core10.getTypedArrayConstructor)(dataType);
2583
+ const typedArray = attribute instanceof import_core10.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
3005
2584
  return typedArray.toString();
3006
2585
  }
3007
2586
  };
3008
2587
  var Model = _Model;
3009
2588
  __publicField(Model, "defaultProps", {
3010
- ...import_core12.RenderPipeline.defaultProps,
2589
+ ...import_core10.RenderPipeline.defaultProps,
3011
2590
  source: void 0,
3012
2591
  vs: null,
3013
2592
  fs: null,
@@ -3020,6 +2599,8 @@ __publicField(Model, "defaultProps", {
3020
2599
  indexBuffer: null,
3021
2600
  attributes: {},
3022
2601
  constantAttributes: {},
2602
+ bindings: {},
2603
+ uniforms: {},
3023
2604
  varyings: [],
3024
2605
  isInstanced: void 0,
3025
2606
  instanceCount: 0,
@@ -3028,14 +2609,14 @@ __publicField(Model, "defaultProps", {
3028
2609
  pipelineFactory: void 0,
3029
2610
  shaderFactory: void 0,
3030
2611
  transformFeedback: void 0,
3031
- shaderAssembler: import_shadertools3.ShaderAssembler.getDefaultShaderAssembler(),
2612
+ shaderAssembler: import_shadertools2.ShaderAssembler.getDefaultShaderAssembler(),
3032
2613
  debugShaders: void 0,
3033
2614
  disableWarnings: void 0
3034
2615
  });
3035
2616
  function shaderModuleHasUniforms(module2) {
3036
2617
  return Boolean(module2.uniformTypes && !isObjectEmpty(module2.uniformTypes));
3037
2618
  }
3038
- function getPlatformInfo2(device) {
2619
+ function getPlatformInfo(device) {
3039
2620
  return {
3040
2621
  type: device.type,
3041
2622
  shaderLanguage: device.info.shadingLanguage,
@@ -3053,8 +2634,8 @@ function isObjectEmpty(obj) {
3053
2634
  }
3054
2635
 
3055
2636
  // dist/compute/buffer-transform.js
3056
- var import_core13 = require("@luma.gl/core");
3057
- var import_shadertools4 = require("@luma.gl/shadertools");
2637
+ var import_core11 = require("@luma.gl/core");
2638
+ var import_shadertools3 = require("@luma.gl/shadertools");
3058
2639
  var _BufferTransform = class {
3059
2640
  device;
3060
2641
  model;
@@ -3070,7 +2651,7 @@ var _BufferTransform = class {
3070
2651
  this.device = device;
3071
2652
  this.model = new Model(this.device, {
3072
2653
  id: props.id || "buffer-transform-model",
3073
- fs: props.fs || (0, import_shadertools4.getPassthroughFS)(),
2654
+ fs: props.fs || (0, import_shadertools3.getPassthroughFS)(),
3074
2655
  topology: props.topology || "point-list",
3075
2656
  varyings: props.outputs || props.varyings,
3076
2657
  ...props
@@ -3116,7 +2697,7 @@ var _BufferTransform = class {
3116
2697
  if (!result) {
3117
2698
  throw new Error("BufferTransform#getBuffer");
3118
2699
  }
3119
- if (result instanceof import_core13.Buffer) {
2700
+ if (result instanceof import_core11.Buffer) {
3120
2701
  return result.readAsync();
3121
2702
  }
3122
2703
  const { buffer, byteOffset = 0, byteLength = buffer.byteLength } = result;
@@ -3131,7 +2712,7 @@ __publicField(BufferTransform, "defaultProps", {
3131
2712
  });
3132
2713
 
3133
2714
  // dist/compute/texture-transform.js
3134
- var import_shadertools5 = require("@luma.gl/shadertools");
2715
+ var import_shadertools4 = require("@luma.gl/shadertools");
3135
2716
  var FS_OUTPUT_VARIABLE = "transform_output";
3136
2717
  var TextureTransform = class {
3137
2718
  device;
@@ -3154,7 +2735,7 @@ var TextureTransform = class {
3154
2735
  });
3155
2736
  this.model = new Model(this.device, {
3156
2737
  id: props.id || uid("texture-transform-model"),
3157
- fs: props.fs || (0, import_shadertools5.getPassthroughFS)({
2738
+ fs: props.fs || (0, import_shadertools4.getPassthroughFS)({
3158
2739
  input: props.targetTextureVarying,
3159
2740
  inputChannels: props.targetTextureChannels,
3160
2741
  output: FS_OUTPUT_VARIABLE
@@ -3324,9 +2905,9 @@ var Geometry = class {
3324
2905
  var CLIPSPACE_VERTEX_SHADER_WGSL = (
3325
2906
  /* wgsl */
3326
2907
  `struct VertexInputs {
3327
- @location(0) clipSpacePosition: vec2<f32>,
3328
- @location(1) texCoord: vec2<f32>,
3329
- @location(2) coordinate: vec2<f32>
2908
+ @location(0) clipSpacePositions: vec2<f32>,
2909
+ @location(1) texCoords: vec2<f32>,
2910
+ @location(2) coordinates: vec2<f32>
3330
2911
  }
3331
2912
 
3332
2913
  struct FragmentInputs {
@@ -3339,10 +2920,10 @@ struct FragmentInputs {
3339
2920
  @vertex
3340
2921
  fn vertexMain(inputs: VertexInputs) -> FragmentInputs {
3341
2922
  var outputs: FragmentInputs;
3342
- outputs.Position = vec4(inputs.clipSpacePosition, 0., 1.);
3343
- outputs.position = inputs.clipSpacePosition;
3344
- outputs.coordinate = inputs.coordinate;
3345
- outputs.uv = inputs.texCoord;
2923
+ outputs.Position = vec4(inputs.clipSpacePositions, 0., 1.);
2924
+ outputs.position = inputs.clipSpacePositions;
2925
+ outputs.coordinate = inputs.coordinates;
2926
+ outputs.uv = inputs.texCoords;
3346
2927
  return outputs;
3347
2928
  }
3348
2929
  `
@@ -3408,15 +2989,15 @@ struct backgroundUniforms {
3408
2989
  };
3409
2990
  @group(0) @binding(2) var<uniform> background: backgroundUniforms;
3410
2991
 
3411
- fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
2992
+ fn billboardTexture_getTextureUV(uv: vec2<f32>) -> vec2<f32> {
3412
2993
  let scale: vec2<f32> = background.scale;
3413
- var position: vec2<f32> = (coordinates - vec2<f32>(0.5, 0.5)) / scale + vec2<f32>(0.5, 0.5);
2994
+ var position: vec2<f32> = (uv - vec2<f32>(0.5, 0.5)) / scale + vec2<f32>(0.5, 0.5);
3414
2995
  return position;
3415
2996
  }
3416
2997
 
3417
2998
  @fragment
3418
2999
  fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
3419
- let position: vec2<f32> = billboardTexture_getTextureUV(inputs.coordinate);
3000
+ let position: vec2<f32> = billboardTexture_getTextureUV(inputs.uv);
3420
3001
  return textureSample(backgroundTexture, backgroundTextureSampler, position);
3421
3002
  }
3422
3003
  `
@@ -3450,20 +3031,22 @@ var BackgroundTextureModel = class extends ClipSpace {
3450
3031
  backgroundTexture = null;
3451
3032
  constructor(device, props) {
3452
3033
  super(device, {
3034
+ ...props,
3453
3035
  id: props.id || "background-texture-model",
3454
3036
  source: BACKGROUND_FS_WGSL,
3455
3037
  fs: BACKGROUND_FS,
3456
- modules: [backgroundModule],
3038
+ modules: [...props.modules || [], backgroundModule],
3457
3039
  parameters: {
3458
3040
  depthWriteEnabled: false,
3041
+ ...props.parameters || {},
3459
3042
  ...props.blend ? {
3460
3043
  blend: true,
3461
3044
  blendColorOperation: "add",
3462
3045
  blendAlphaOperation: "add",
3463
- blendColorSrcFactor: "one",
3464
- blendColorDstFactor: "one-minus-src",
3465
- blendAlphaSrcFactor: "one",
3466
- blendAlphaDstFactor: "one-minus-src-alpha"
3046
+ blendColorSrcFactor: "one-minus-dst-alpha",
3047
+ blendColorDstFactor: "one",
3048
+ blendAlphaSrcFactor: "one-minus-dst-alpha",
3049
+ blendAlphaDstFactor: "one"
3467
3050
  } : {}
3468
3051
  }
3469
3052
  });
@@ -3514,14 +3097,19 @@ var BackgroundTextureModel = class extends ClipSpace {
3514
3097
  };
3515
3098
 
3516
3099
  // dist/scenegraph/scenegraph-node.js
3517
- var import_core14 = require("@math.gl/core");
3100
+ var import_core12 = require("@math.gl/core");
3101
+ function assert(condition, message) {
3102
+ if (!condition) {
3103
+ throw new Error(message);
3104
+ }
3105
+ }
3518
3106
  var ScenegraphNode = class {
3519
3107
  id;
3520
- matrix = new import_core14.Matrix4();
3108
+ matrix = new import_core12.Matrix4();
3521
3109
  display = true;
3522
- position = new import_core14.Vector3();
3523
- rotation = new import_core14.Vector3();
3524
- scale = new import_core14.Vector3(1, 1, 1);
3110
+ position = new import_core12.Vector3();
3111
+ rotation = new import_core12.Vector3();
3112
+ scale = new import_core12.Vector3(1, 1, 1);
3525
3113
  userData = {};
3526
3114
  props = {};
3527
3115
  constructor(props = {}) {
@@ -3546,14 +3134,17 @@ var ScenegraphNode = class {
3546
3134
  return `{type: ScenegraphNode, id: ${this.id})}`;
3547
3135
  }
3548
3136
  setPosition(position) {
3137
+ assert(position.length === 3, "setPosition requires vector argument");
3549
3138
  this.position = position;
3550
3139
  return this;
3551
3140
  }
3552
3141
  setRotation(rotation) {
3142
+ assert(rotation.length === 3 || rotation.length === 4, "setRotation requires vector argument");
3553
3143
  this.rotation = rotation;
3554
3144
  return this;
3555
3145
  }
3556
3146
  setScale(scale) {
3147
+ assert(scale.length === 3, "setScale requires vector argument");
3557
3148
  this.scale = scale;
3558
3149
  return this;
3559
3150
  }
@@ -3581,17 +3172,18 @@ var ScenegraphNode = class {
3581
3172
  return this;
3582
3173
  }
3583
3174
  updateMatrix() {
3584
- const pos = this.position;
3585
- const rot = this.rotation;
3586
- const scale = this.scale;
3587
3175
  this.matrix.identity();
3588
- this.matrix.translate(pos);
3589
- this.matrix.rotateXYZ(rot);
3590
- this.matrix.scale(scale);
3176
+ this.matrix.translate(this.position);
3177
+ if (this.rotation.length === 4) {
3178
+ const rotationMatrix = new import_core12.Matrix4().fromQuaternion(this.rotation);
3179
+ this.matrix.multiplyRight(rotationMatrix);
3180
+ } else {
3181
+ this.matrix.rotateXYZ(this.rotation);
3182
+ }
3183
+ this.matrix.scale(this.scale);
3591
3184
  return this;
3592
3185
  }
3593
- update(options = {}) {
3594
- const { position, rotation, scale } = options;
3186
+ update({ position, rotation, scale } = {}) {
3595
3187
  if (position) {
3596
3188
  this.setPosition(position);
3597
3189
  }
@@ -3606,7 +3198,7 @@ var ScenegraphNode = class {
3606
3198
  }
3607
3199
  getCoordinateUniforms(viewMatrix, modelMatrix) {
3608
3200
  modelMatrix = modelMatrix || this.matrix;
3609
- const worldMatrix = new import_core14.Matrix4(viewMatrix).multiplyRight(modelMatrix);
3201
+ const worldMatrix = new import_core12.Matrix4(viewMatrix).multiplyRight(modelMatrix);
3610
3202
  const worldInverse = worldMatrix.invert();
3611
3203
  const worldInverseTranspose = worldInverse.transpose();
3612
3204
  return {
@@ -3641,16 +3233,17 @@ var ScenegraphNode = class {
3641
3233
  }
3642
3234
  */
3643
3235
  _setScenegraphNodeProps(props) {
3644
- if ("position" in props) {
3236
+ if (props == null ? void 0 : props.position) {
3645
3237
  this.setPosition(props.position);
3646
3238
  }
3647
- if ("rotation" in props) {
3239
+ if (props == null ? void 0 : props.rotation) {
3648
3240
  this.setRotation(props.rotation);
3649
3241
  }
3650
- if ("scale" in props) {
3242
+ if (props == null ? void 0 : props.scale) {
3651
3243
  this.setScale(props.scale);
3652
3244
  }
3653
- if ("matrix" in props) {
3245
+ this.updateMatrix();
3246
+ if (props == null ? void 0 : props.matrix) {
3654
3247
  this.setMatrix(props.matrix);
3655
3248
  }
3656
3249
  Object.assign(this.props, props);
@@ -3658,14 +3251,14 @@ var ScenegraphNode = class {
3658
3251
  };
3659
3252
 
3660
3253
  // dist/scenegraph/group-node.js
3661
- var import_core15 = require("@math.gl/core");
3662
- var import_core16 = require("@luma.gl/core");
3254
+ var import_core13 = require("@math.gl/core");
3255
+ var import_core14 = require("@luma.gl/core");
3663
3256
  var GroupNode = class extends ScenegraphNode {
3664
3257
  children;
3665
3258
  constructor(props = {}) {
3666
3259
  props = Array.isArray(props) ? { children: props } : props;
3667
3260
  const { children = [] } = props;
3668
- import_core16.log.assert(children.every((child) => child instanceof ScenegraphNode), "every child must an instance of ScenegraphNode");
3261
+ import_core14.log.assert(children.every((child) => child instanceof ScenegraphNode), "every child must an instance of ScenegraphNode");
3669
3262
  super(props);
3670
3263
  this.children = children;
3671
3264
  }
@@ -3680,12 +3273,12 @@ var GroupNode = class extends ScenegraphNode {
3680
3273
  return;
3681
3274
  }
3682
3275
  const [min, max] = bounds;
3683
- const center = new import_core15.Vector3(min).add(max).divide([2, 2, 2]);
3276
+ const center = new import_core13.Vector3(min).add(max).divide([2, 2, 2]);
3684
3277
  worldMatrix.transformAsPoint(center, center);
3685
- const halfSize = new import_core15.Vector3(max).subtract(min).divide([2, 2, 2]);
3278
+ const halfSize = new import_core13.Vector3(max).subtract(min).divide([2, 2, 2]);
3686
3279
  worldMatrix.transformAsVector(halfSize, halfSize);
3687
3280
  for (let v = 0; v < 8; v++) {
3688
- const position = new import_core15.Vector3(v & 1 ? -1 : 1, v & 2 ? -1 : 1, v & 4 ? -1 : 1).multiply(halfSize).add(center);
3281
+ const position = new import_core13.Vector3(v & 1 ? -1 : 1, v & 2 ? -1 : 1, v & 4 ? -1 : 1).multiply(halfSize).add(center);
3689
3282
  for (let i = 0; i < 3; i++) {
3690
3283
  result[0][i] = Math.min(result[0][i], position[i]);
3691
3284
  result[1][i] = Math.max(result[1][i], position[i]);
@@ -3725,8 +3318,8 @@ var GroupNode = class extends ScenegraphNode {
3725
3318
  this.children = [];
3726
3319
  return this;
3727
3320
  }
3728
- traverse(visitor, { worldMatrix = new import_core15.Matrix4() } = {}) {
3729
- const modelMatrix = new import_core15.Matrix4(worldMatrix).multiplyRight(this.matrix);
3321
+ traverse(visitor, { worldMatrix = new import_core13.Matrix4() } = {}) {
3322
+ const modelMatrix = new import_core13.Matrix4(worldMatrix).multiplyRight(this.matrix);
3730
3323
  for (const child of this.children) {
3731
3324
  if (child instanceof GroupNode) {
3732
3325
  child.traverse(visitor, { worldMatrix: modelMatrix });
@@ -3735,6 +3328,17 @@ var GroupNode = class extends ScenegraphNode {
3735
3328
  }
3736
3329
  }
3737
3330
  }
3331
+ preorderTraversal(visitor, { worldMatrix = new import_core13.Matrix4() } = {}) {
3332
+ const modelMatrix = new import_core13.Matrix4(worldMatrix).multiplyRight(this.matrix);
3333
+ visitor(this, { worldMatrix: modelMatrix });
3334
+ for (const child of this.children) {
3335
+ if (child instanceof GroupNode) {
3336
+ child.preorderTraversal(visitor, { worldMatrix: modelMatrix });
3337
+ } else {
3338
+ visitor(child, { worldMatrix: modelMatrix });
3339
+ }
3340
+ }
3341
+ }
3738
3342
  };
3739
3343
 
3740
3344
  // dist/scenegraph/model-node.js
@@ -4508,7 +4112,7 @@ var CylinderGeometry = class extends TruncatedConeGeometry {
4508
4112
  };
4509
4113
 
4510
4114
  // dist/geometries/ico-sphere-geometry.js
4511
- var import_core17 = require("@math.gl/core");
4115
+ var import_core15 = require("@math.gl/core");
4512
4116
  var ICO_POSITIONS = [-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 1, 0, -1, 0, 1, 0, 0];
4513
4117
  var ICO_INDICES = [3, 4, 5, 3, 5, 1, 3, 1, 0, 3, 0, 4, 4, 0, 2, 4, 2, 5, 2, 0, 1, 5, 2, 1];
4514
4118
  var IcoSphereGeometry = class extends Geometry {
@@ -4606,7 +4210,7 @@ function tesselateIcosaHedron(props) {
4606
4210
  const u3 = 1 - phi3 / PI2;
4607
4211
  const vec1 = [x3 - x2, y3 - y2, z3 - z2];
4608
4212
  const vec2 = [x1 - x2, y1 - y2, z1 - z2];
4609
- const normal = new import_core17.Vector3(vec1).cross(vec2).normalize();
4213
+ const normal = new import_core15.Vector3(vec1).cross(vec2).normalize();
4610
4214
  let newIndex;
4611
4215
  if ((u1 === 0 || u2 === 0 || u3 === 0) && (u1 === 0 || u1 > 0.5) && (u2 === 0 || u2 > 0.5) && (u3 === 0 || u3 > 0.5)) {
4612
4216
  positions.push(positions[in1 + 0], positions[in1 + 1], positions[in1 + 2]);
@@ -4893,10 +4497,10 @@ async function loadImage(url, opts) {
4893
4497
  }
4894
4498
 
4895
4499
  // dist/passes/shader-pass-renderer.js
4896
- var import_shadertools6 = require("@luma.gl/shadertools");
4500
+ var import_shadertools5 = require("@luma.gl/shadertools");
4897
4501
 
4898
4502
  // dist/compute/swap.js
4899
- var import_core18 = require("@luma.gl/core");
4503
+ var import_core16 = require("@luma.gl/core");
4900
4504
  var Swap = class {
4901
4505
  id;
4902
4506
  /** The current resource - usually the source for renders or computations */
@@ -4929,7 +4533,7 @@ var SwapFramebuffers = class extends Swap {
4929
4533
  let colorAttachments = (_a = props.colorAttachments) == null ? void 0 : _a.map((colorAttachment) => typeof colorAttachment !== "string" ? colorAttachment : device.createTexture({
4930
4534
  id: `${props.id}-texture-0`,
4931
4535
  format: colorAttachment,
4932
- usage: import_core18.Texture.SAMPLE | import_core18.Texture.RENDER | import_core18.Texture.COPY_SRC | import_core18.Texture.COPY_DST,
4536
+ usage: import_core16.Texture.SAMPLE | import_core16.Texture.RENDER | import_core16.Texture.COPY_SRC | import_core16.Texture.COPY_DST,
4933
4537
  width,
4934
4538
  height
4935
4539
  }));
@@ -4937,7 +4541,7 @@ var SwapFramebuffers = class extends Swap {
4937
4541
  colorAttachments = (_b = props.colorAttachments) == null ? void 0 : _b.map((colorAttachment) => typeof colorAttachment !== "string" ? colorAttachment : device.createTexture({
4938
4542
  id: `${props.id}-texture-1`,
4939
4543
  format: colorAttachment,
4940
- usage: import_core18.Texture.SAMPLE | import_core18.Texture.RENDER | import_core18.Texture.COPY_SRC | import_core18.Texture.COPY_DST,
4544
+ usage: import_core16.Texture.SAMPLE | import_core16.Texture.RENDER | import_core16.Texture.COPY_SRC | import_core16.Texture.COPY_DST,
4941
4545
  width,
4942
4546
  height
4943
4547
  }));
@@ -5000,26 +4604,16 @@ function getFragmentShaderForRenderPass(options) {
5000
4604
  function getFilterShaderWGSL(func) {
5001
4605
  return (
5002
4606
  /* wgsl */
5003
- `// Binding 0:1 is reserved for shader passes
5004
- // @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
5005
- @group(0) @binding(1) var texture: texture_2d<f32>;
5006
- @group(0) @binding(2) var textureSampler: sampler;
5007
-
5008
- // This needs to be aligned with
5009
- // struct FragmentInputs {
5010
- // @location(0) fragUV: vec2f,
5011
- // @location(1) fragPosition: vec4f,
5012
- // @location(2) fragCoordinate: vec4f
5013
- // };
4607
+ `@group(0) @binding(0) var sourceTexture: texture_2d<f32>;
4608
+ @group(0) @binding(2) var sourceTextureSampler: sampler;
5014
4609
 
5015
4610
  @fragment
5016
4611
  fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
5017
- let fragUV = inputs.uv;
5018
- let fragCoordinate = inputs.coordinate;
5019
- let texSize = vec2f(textureDimensions(texture, 0));
4612
+ let texCoord = inputs.coordinate;
4613
+ let texSize = vec2f(textureDimensions(sourceTexture));
5020
4614
 
5021
- var fragColor = textureSample(texture, textureSampler, fragUV);
5022
- fragColor = ${func}(fragColor, texSize, fragCoordinate);
4615
+ var fragColor = textureSample(sourceTexture, sourceTextureSampler, texCoord);
4616
+ fragColor = ${func}(fragColor, texSize, texCoord);
5023
4617
  return fragColor;
5024
4618
  }
5025
4619
  `
@@ -5028,23 +4622,14 @@ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
5028
4622
  function getSamplerShaderWGSL(func) {
5029
4623
  return (
5030
4624
  /* wgsl */
5031
- `// Binding 0:1 is reserved for shader passes
5032
- @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
5033
- @group(0) @binding(1) var texture: texture_2d<f32>;
5034
- @group(0) @binding(2) var sampler: sampler;
5035
-
5036
- struct FragmentInputs = {
5037
- @location(0) fragUV: vec2f,
5038
- @location(1) fragPosition: vec4f,
5039
- @location(2) fragCoordinate: vec4f
5040
- };
4625
+ `@group(0) @binding(0) var sourceTexture: texture_2d<f32>;
4626
+ @group(0) @binding(2) var sourceTextureSampler: sampler;
5041
4627
 
5042
4628
  @fragment
5043
4629
  fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
5044
- let texSize = vec2f(textureDimensions(texture, 0));
5045
- var fragColor = textureSample(texture, sampler, fragUV);
5046
- fragColor = ${func}(fragColor, texSize, texCoord);
5047
- return fragColor;
4630
+ let texCoord = inputs.coordinate;
4631
+ let texSize = vec2f(textureDimensions(sourceTexture));
4632
+ return ${func}(sourceTexture, sourceTextureSampler, texSize, texCoord);
5048
4633
  }
5049
4634
  `
5050
4635
  );
@@ -5103,12 +4688,10 @@ var ShaderPassRenderer = class {
5103
4688
  shaderInputs;
5104
4689
  passRenderers;
5105
4690
  swapFramebuffers;
5106
- /** For rendering to the screen */
5107
- clipSpace;
5108
4691
  textureModel;
5109
4692
  constructor(device, props) {
5110
4693
  this.device = device;
5111
- props.shaderPasses.map((shaderPass) => (0, import_shadertools6.initializeShaderModule)(shaderPass));
4694
+ props.shaderPasses.map((shaderPass) => (0, import_shadertools5.initializeShaderModule)(shaderPass));
5112
4695
  const modules = props.shaderPasses.reduce((object, shaderPass) => ({ ...object, [shaderPass.name]: shaderPass }), {});
5113
4696
  this.shaderInputs = props.shaderInputs || new ShaderInputs(modules);
5114
4697
  const size = device.getCanvasContext().getDrawingBufferSize();
@@ -5120,33 +4703,6 @@ var ShaderPassRenderer = class {
5120
4703
  this.textureModel = new BackgroundTextureModel(device, {
5121
4704
  backgroundTexture: this.swapFramebuffers.current.colorAttachments[0].texture
5122
4705
  });
5123
- this.clipSpace = new ClipSpace(device, {
5124
- source: (
5125
- /* wgsl */
5126
- ` @group(0) @binding(0) var sourceTexture: texture_2d<f32>;
5127
- @group(0) @binding(1) var sourceTextureSampler: sampler;
5128
-
5129
- @fragment
5130
- fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
5131
- let texCoord: vec2<f32> = inputs.coordinate;
5132
- return textureSample(sourceTexture, sourceTextureSampler, texCoord);
5133
- }
5134
- `
5135
- ),
5136
- fs: (
5137
- /* glsl */
5138
- `#version 300 es
5139
-
5140
- uniform sampler2D sourceTexture;
5141
- in vec2 uv;
5142
- out vec4 fragColor;
5143
-
5144
- void main() {
5145
- fragColor = texture(sourceTexture, uv);
5146
- }
5147
- `
5148
- )
5149
- });
5150
4706
  this.passRenderers = props.shaderPasses.map((shaderPass) => new PassRenderer(device, shaderPass));
5151
4707
  }
5152
4708
  /** Destroys resources created by this ShaderPassRenderer */
@@ -5155,7 +4711,6 @@ void main() {
5155
4711
  subPassRenderer.destroy();
5156
4712
  }
5157
4713
  this.swapFramebuffers.destroy();
5158
- this.clipSpace.destroy();
5159
4714
  this.textureModel.destroy();
5160
4715
  }
5161
4716
  resize(size) {
@@ -5167,15 +4722,15 @@ void main() {
5167
4722
  if (!outputTexture) {
5168
4723
  return false;
5169
4724
  }
5170
- const framebuffer = this.device.getDefaultCanvasContext().getCurrentFramebuffer({ depthStencilAttachment: false });
4725
+ const framebuffer = this.device.getDefaultCanvasContext().getCurrentFramebuffer({ depthStencilFormat: false });
5171
4726
  const renderPass = this.device.beginRenderPass({
5172
4727
  id: "shader-pass-renderer-to-screen",
5173
4728
  framebuffer,
5174
4729
  // clearColor: [1, 1, 0, 1],
5175
- clearDepth: 1
4730
+ clearDepth: false
5176
4731
  });
5177
- this.clipSpace.setBindings({ sourceTexture: outputTexture });
5178
- this.clipSpace.draw(renderPass);
4732
+ this.textureModel.setProps({ backgroundTexture: outputTexture });
4733
+ this.textureModel.draw(renderPass);
5179
4734
  renderPass.end();
5180
4735
  return true;
5181
4736
  }
@@ -5280,6 +4835,218 @@ var SubPassRenderer = class {
5280
4835
  }
5281
4836
  };
5282
4837
 
4838
+ // dist/compute/computation.js
4839
+ var import_core17 = require("@luma.gl/core");
4840
+ var import_shadertools6 = require("@luma.gl/shadertools");
4841
+ var import_types2 = require("@math.gl/types");
4842
+ var LOG_DRAW_PRIORITY2 = 2;
4843
+ var LOG_DRAW_TIMEOUT2 = 1e4;
4844
+ var _Computation = class {
4845
+ device;
4846
+ id;
4847
+ pipelineFactory;
4848
+ shaderFactory;
4849
+ userData = {};
4850
+ /** Bindings (textures, samplers, uniform buffers) */
4851
+ bindings = {};
4852
+ /** The underlying GPU pipeline. */
4853
+ pipeline;
4854
+ /** Assembled compute shader source */
4855
+ source;
4856
+ /** the underlying compiled compute shader */
4857
+ // @ts-ignore Set in function called from constructor
4858
+ shader;
4859
+ /** ShaderInputs instance */
4860
+ shaderInputs;
4861
+ // @ts-ignore Set in function called from constructor
4862
+ _uniformStore;
4863
+ _pipelineNeedsUpdate = "newly created";
4864
+ _getModuleUniforms;
4865
+ props;
4866
+ _destroyed = false;
4867
+ constructor(device, props) {
4868
+ var _a, _b, _c;
4869
+ if (device.type !== "webgpu") {
4870
+ throw new Error("Computation is only supported in WebGPU");
4871
+ }
4872
+ this.props = { ..._Computation.defaultProps, ...props };
4873
+ props = this.props;
4874
+ this.id = props.id || uid("model");
4875
+ this.device = device;
4876
+ Object.assign(this.userData, props.userData);
4877
+ const moduleMap = Object.fromEntries(((_a = this.props.modules) == null ? void 0 : _a.map((module2) => [module2.name, module2])) || []);
4878
+ this.shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap);
4879
+ this.setShaderInputs(this.shaderInputs);
4880
+ this.props.shaderLayout ||= device.getShaderLayout(this.props.source);
4881
+ const platformInfo = getPlatformInfo2(device);
4882
+ const modules = (((_b = this.props.modules) == null ? void 0 : _b.length) > 0 ? this.props.modules : (_c = this.shaderInputs) == null ? void 0 : _c.getModules()) || [];
4883
+ this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
4884
+ this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
4885
+ const { source: source3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleWGSLShader({
4886
+ platformInfo,
4887
+ ...this.props,
4888
+ modules
4889
+ });
4890
+ this.source = source3;
4891
+ this._getModuleUniforms = getUniforms2;
4892
+ this.pipeline = this._updatePipeline();
4893
+ if (props.bindings) {
4894
+ this.setBindings(props.bindings);
4895
+ }
4896
+ Object.seal(this);
4897
+ }
4898
+ destroy() {
4899
+ if (this._destroyed)
4900
+ return;
4901
+ this.pipelineFactory.release(this.pipeline);
4902
+ this.shaderFactory.release(this.shader);
4903
+ this._uniformStore.destroy();
4904
+ this._destroyed = true;
4905
+ }
4906
+ // Draw call
4907
+ predraw() {
4908
+ this.updateShaderInputs();
4909
+ }
4910
+ dispatch(computePass, x, y, z) {
4911
+ try {
4912
+ this._logDrawCallStart();
4913
+ this.pipeline = this._updatePipeline();
4914
+ this.pipeline.setBindings(this.bindings);
4915
+ computePass.setPipeline(this.pipeline);
4916
+ computePass.setBindings([]);
4917
+ computePass.dispatch(x, y, z);
4918
+ } finally {
4919
+ this._logDrawCallEnd();
4920
+ }
4921
+ }
4922
+ // Update fixed fields (can trigger pipeline rebuild)
4923
+ // Update dynamic fields
4924
+ /**
4925
+ * Updates the vertex count (used in draw calls)
4926
+ * @note Any attributes with stepMode=vertex need to be at least this big
4927
+ */
4928
+ setVertexCount(vertexCount) {
4929
+ }
4930
+ /**
4931
+ * Updates the instance count (used in draw calls)
4932
+ * @note Any attributes with stepMode=instance need to be at least this big
4933
+ */
4934
+ setInstanceCount(instanceCount) {
4935
+ }
4936
+ setShaderInputs(shaderInputs) {
4937
+ this.shaderInputs = shaderInputs;
4938
+ this._uniformStore = new import_core17.UniformStore(this.shaderInputs.modules);
4939
+ for (const moduleName of Object.keys(this.shaderInputs.modules)) {
4940
+ const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
4941
+ this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
4942
+ }
4943
+ }
4944
+ /**
4945
+ * Updates shader module settings (which results in uniforms being set)
4946
+ */
4947
+ setShaderModuleProps(props) {
4948
+ const uniforms = this._getModuleUniforms(props);
4949
+ const keys = Object.keys(uniforms).filter((k) => {
4950
+ const uniform = uniforms[k];
4951
+ return !(0, import_types2.isNumericArray)(uniform) && typeof uniform !== "number" && typeof uniform !== "boolean";
4952
+ });
4953
+ const bindings = {};
4954
+ for (const k of keys) {
4955
+ bindings[k] = uniforms[k];
4956
+ delete uniforms[k];
4957
+ }
4958
+ }
4959
+ updateShaderInputs() {
4960
+ this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
4961
+ }
4962
+ /**
4963
+ * Sets bindings (textures, samplers, uniform buffers)
4964
+ */
4965
+ setBindings(bindings) {
4966
+ Object.assign(this.bindings, bindings);
4967
+ }
4968
+ _setPipelineNeedsUpdate(reason) {
4969
+ this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
4970
+ }
4971
+ _updatePipeline() {
4972
+ if (this._pipelineNeedsUpdate) {
4973
+ let prevShader = null;
4974
+ if (this.pipeline) {
4975
+ import_core17.log.log(1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`)();
4976
+ prevShader = this.shader;
4977
+ }
4978
+ this._pipelineNeedsUpdate = false;
4979
+ this.shader = this.shaderFactory.createShader({
4980
+ id: `${this.id}-fragment`,
4981
+ stage: "compute",
4982
+ source: this.source,
4983
+ debugShaders: this.props.debugShaders
4984
+ });
4985
+ this.pipeline = this.pipelineFactory.createComputePipeline({
4986
+ ...this.props,
4987
+ shader: this.shader
4988
+ });
4989
+ if (prevShader) {
4990
+ this.shaderFactory.release(prevShader);
4991
+ }
4992
+ }
4993
+ return this.pipeline;
4994
+ }
4995
+ /** Throttle draw call logging */
4996
+ _lastLogTime = 0;
4997
+ _logOpen = false;
4998
+ _logDrawCallStart() {
4999
+ const logDrawTimeout = import_core17.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT2;
5000
+ if (import_core17.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
5001
+ return;
5002
+ }
5003
+ this._lastLogTime = Date.now();
5004
+ this._logOpen = true;
5005
+ import_core17.log.group(LOG_DRAW_PRIORITY2, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core17.log.level <= 2 })();
5006
+ }
5007
+ _logDrawCallEnd() {
5008
+ if (this._logOpen) {
5009
+ const uniformTable = this.shaderInputs.getDebugTable();
5010
+ import_core17.log.table(LOG_DRAW_PRIORITY2, uniformTable)();
5011
+ import_core17.log.groupEnd(LOG_DRAW_PRIORITY2)();
5012
+ this._logOpen = false;
5013
+ }
5014
+ }
5015
+ _drawCount = 0;
5016
+ // TODO - fix typing of luma data types
5017
+ _getBufferOrConstantValues(attribute, dataType) {
5018
+ const TypedArrayConstructor = (0, import_core17.getTypedArrayConstructor)(dataType);
5019
+ const typedArray = attribute instanceof import_core17.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
5020
+ return typedArray.toString();
5021
+ }
5022
+ };
5023
+ var Computation = _Computation;
5024
+ __publicField(Computation, "defaultProps", {
5025
+ ...import_core17.ComputePipeline.defaultProps,
5026
+ id: "unnamed",
5027
+ handle: void 0,
5028
+ userData: {},
5029
+ source: "",
5030
+ modules: [],
5031
+ defines: {},
5032
+ bindings: void 0,
5033
+ shaderInputs: void 0,
5034
+ pipelineFactory: void 0,
5035
+ shaderFactory: void 0,
5036
+ shaderAssembler: import_shadertools6.ShaderAssembler.getDefaultShaderAssembler(),
5037
+ debugShaders: void 0
5038
+ });
5039
+ function getPlatformInfo2(device) {
5040
+ return {
5041
+ type: device.type,
5042
+ shaderLanguage: device.info.shadingLanguage,
5043
+ shaderLanguageVersion: device.info.shadingLanguageVersion,
5044
+ gpu: device.info.gpu,
5045
+ // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
5046
+ features: device.features
5047
+ };
5048
+ }
5049
+
5283
5050
  // dist/modules/picking/picking-uniforms.js
5284
5051
  var DEFAULT_HIGHLIGHT_COLOR = [0, 1, 1, 1];
5285
5052
  var INVALID_INDEX = -1;
@@ -5475,12 +5242,6 @@ const INDEX_PICKING_MODE_INSTANCE = 0;
5475
5242
  const INDEX_PICKING_MODE_CUSTOM = 1;
5476
5243
  const INDEX_PICKING_INVALID_INDEX = ${INVALID_INDEX}; // 2^32 - 1
5477
5244
 
5478
- struct indexPickingFragmentInputs = {
5479
- objectIndex: int32;
5480
- };
5481
-
5482
- let indexPickingFragmentInputs: indexPickingFragmentInputs;
5483
-
5484
5245
  /**
5485
5246
  * Vertex shaders should call this function to set the object index.
5486
5247
  * If using instance or vertex mode, argument will be ignored, 0 can be supplied.