@luma.gl/engine 9.1.9 → 9.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +5 -0
  2. package/dist/animation-loop/animation-loop.d.ts +12 -12
  3. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  4. package/dist/animation-loop/animation-loop.js +26 -62
  5. package/dist/animation-loop/animation-loop.js.map +1 -1
  6. package/dist/animation-loop/animation-props.d.ts +3 -4
  7. package/dist/animation-loop/animation-props.d.ts.map +1 -1
  8. package/dist/animation-loop/make-animation-loop.d.ts +4 -1
  9. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  10. package/dist/animation-loop/make-animation-loop.js +39 -7
  11. package/dist/animation-loop/make-animation-loop.js.map +1 -1
  12. package/dist/async-texture/async-texture.d.ts +106 -2
  13. package/dist/async-texture/async-texture.d.ts.map +1 -1
  14. package/dist/async-texture/async-texture.js +281 -13
  15. package/dist/async-texture/async-texture.js.map +1 -1
  16. package/dist/compute/computation.d.ts +1 -1
  17. package/dist/compute/computation.d.ts.map +1 -1
  18. package/dist/compute/computation.js +2 -2
  19. package/dist/compute/computation.js.map +1 -1
  20. package/dist/compute/swap.d.ts.map +1 -1
  21. package/dist/compute/swap.js +6 -2
  22. package/dist/compute/swap.js.map +1 -1
  23. package/dist/compute/texture-transform.d.ts.map +1 -1
  24. package/dist/compute/texture-transform.js +4 -2
  25. package/dist/compute/texture-transform.js.map +1 -1
  26. package/dist/debug/copy-texture-to-image.d.ts +23 -1
  27. package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
  28. package/dist/debug/copy-texture-to-image.js +37 -1
  29. package/dist/debug/copy-texture-to-image.js.map +1 -1
  30. package/dist/dist.dev.js +566 -232
  31. package/dist/dist.min.js +26 -26
  32. package/dist/factories/pipeline-factory.d.ts +11 -1
  33. package/dist/factories/pipeline-factory.d.ts.map +1 -1
  34. package/dist/factories/pipeline-factory.js +107 -25
  35. package/dist/factories/pipeline-factory.js.map +1 -1
  36. package/dist/factories/shader-factory.d.ts +5 -1
  37. package/dist/factories/shader-factory.d.ts.map +1 -1
  38. package/dist/factories/shader-factory.js +40 -6
  39. package/dist/factories/shader-factory.js.map +1 -1
  40. package/dist/geometries/cube-geometry.d.ts +3 -3
  41. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  42. package/dist/geometry/geometry.d.ts.map +1 -1
  43. package/dist/geometry/geometry.js +3 -2
  44. package/dist/geometry/geometry.js.map +1 -1
  45. package/dist/index.cjs +581 -251
  46. package/dist/index.cjs.map +4 -4
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/model/model.d.ts +4 -25
  51. package/dist/model/model.d.ts.map +1 -1
  52. package/dist/model/model.js +26 -71
  53. package/dist/model/model.js.map +1 -1
  54. package/dist/models/billboard-texture-model.d.ts.map +1 -1
  55. package/dist/models/billboard-texture-model.js +6 -4
  56. package/dist/models/billboard-texture-model.js.map +1 -1
  57. package/dist/modules/picking/legacy-picking-manager.d.ts +1 -1
  58. package/dist/modules/picking/legacy-picking-manager.d.ts.map +1 -1
  59. package/dist/modules/picking/legacy-picking-manager.js +1 -1
  60. package/dist/modules/picking/legacy-picking-manager.js.map +1 -1
  61. package/dist/modules/picking/picking-manager.d.ts +2 -2
  62. package/dist/modules/picking/picking-manager.d.ts.map +1 -1
  63. package/dist/modules/picking/picking-manager.js +2 -2
  64. package/dist/modules/picking/picking-manager.js.map +1 -1
  65. package/dist/passes/get-fragment-shader.js +2 -2
  66. package/dist/passes/shader-pass-renderer.d.ts +4 -4
  67. package/dist/passes/shader-pass-renderer.d.ts.map +1 -1
  68. package/dist/passes/shader-pass-renderer.js +15 -5
  69. package/dist/passes/shader-pass-renderer.js.map +1 -1
  70. package/dist/shader-inputs.js +1 -1
  71. package/dist/shader-inputs.js.map +1 -1
  72. package/dist/utils/buffer-layout-helper.d.ts +12 -0
  73. package/dist/utils/buffer-layout-helper.d.ts.map +1 -0
  74. package/dist/utils/buffer-layout-helper.js +41 -0
  75. package/dist/utils/buffer-layout-helper.js.map +1 -0
  76. package/dist/utils/buffer-layout-order.d.ts +3 -0
  77. package/dist/utils/buffer-layout-order.d.ts.map +1 -0
  78. package/dist/utils/buffer-layout-order.js +16 -0
  79. package/dist/utils/buffer-layout-order.js.map +1 -0
  80. package/package.json +4 -4
  81. package/src/animation-loop/animation-loop.ts +31 -71
  82. package/src/animation-loop/animation-props.ts +3 -5
  83. package/src/animation-loop/make-animation-loop.ts +41 -9
  84. package/src/async-texture/async-texture.ts +386 -23
  85. package/src/async-texture/texture-setters.ts.disabled +296 -0
  86. package/src/compute/computation.ts +3 -3
  87. package/src/compute/swap.ts +7 -2
  88. package/src/compute/texture-transform.ts +4 -2
  89. package/src/debug/copy-texture-to-image.ts +52 -2
  90. package/src/factories/pipeline-factory.ts +122 -26
  91. package/src/factories/shader-factory.ts +43 -7
  92. package/src/geometry/geometry.ts +3 -2
  93. package/src/index.ts +12 -0
  94. package/src/model/model.ts +31 -86
  95. package/src/models/billboard-texture-model.ts +6 -4
  96. package/src/modules/picking/legacy-picking-manager.ts +2 -2
  97. package/src/modules/picking/picking-manager.ts +3 -3
  98. package/src/passes/get-fragment-shader.ts +2 -2
  99. package/src/passes/shader-pass-renderer.ts +18 -8
  100. package/src/shader-inputs.ts +1 -1
  101. package/src/utils/buffer-layout-helper.ts +51 -0
  102. package/src/utils/buffer-layout-order.ts +26 -0
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {Device, Shader, ShaderProps} from '@luma.gl/core';
5
+ import {Device, Shader, ShaderProps, log} from '@luma.gl/core';
6
6
 
7
7
  /** Manages a cached pool of Shaders for reuse. */
8
8
  export class ShaderFactory {
@@ -10,22 +10,39 @@ export class ShaderFactory {
10
10
 
11
11
  /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
12
12
  static getDefaultShaderFactory(device: Device): ShaderFactory {
13
- device._lumaData.defaultShaderFactory ||= new ShaderFactory(device);
14
- return device._lumaData.defaultShaderFactory as ShaderFactory;
13
+ device._lumaData['defaultShaderFactory'] ||= new ShaderFactory(device);
14
+ return device._lumaData['defaultShaderFactory'] as ShaderFactory;
15
15
  }
16
16
 
17
17
  public readonly device: Device;
18
+ readonly cachingEnabled: boolean;
18
19
  readonly destroyPolicy: 'unused' | 'never';
20
+ readonly debug: boolean;
21
+
19
22
  private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
20
23
 
24
+ get [Symbol.toStringTag](): string {
25
+ return 'ShaderFactory';
26
+ }
27
+
28
+ toString(): string {
29
+ return `${this[Symbol.toStringTag]}(${this.device.id})`;
30
+ }
31
+
21
32
  /** @internal */
22
33
  constructor(device: Device) {
23
34
  this.device = device;
24
- this.destroyPolicy = device.props._factoryDestroyPolicy;
35
+ this.cachingEnabled = device.props._cacheShaders;
36
+ this.destroyPolicy = device.props._cacheDestroyPolicy;
37
+ this.debug = true; // device.props.debugFactories;
25
38
  }
26
39
 
27
40
  /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
28
41
  createShader(props: ShaderProps): Shader {
42
+ if (!this.cachingEnabled) {
43
+ return this.device.createShader(props);
44
+ }
45
+
29
46
  const key = this._hashShader(props);
30
47
 
31
48
  let cacheEntry = this._cache[key];
@@ -34,15 +51,27 @@ export class ShaderFactory {
34
51
  ...props,
35
52
  id: props.id ? `${props.id}-cached` : undefined
36
53
  });
37
- this._cache[key] = cacheEntry = {shader, useCount: 0};
54
+ this._cache[key] = cacheEntry = {shader, useCount: 1};
55
+ if (this.debug) {
56
+ log.warn(`${this}: Created new shader ${shader.id}`)();
57
+ }
58
+ } else {
59
+ cacheEntry.useCount++;
60
+ if (this.debug) {
61
+ log.warn(`${this}: Reusing shader ${cacheEntry.shader.id} count=${cacheEntry.useCount}`)();
62
+ }
38
63
  }
39
64
 
40
- cacheEntry.useCount++;
41
65
  return cacheEntry.shader;
42
66
  }
43
67
 
44
68
  /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
45
69
  release(shader: Shader): void {
70
+ if (!this.cachingEnabled) {
71
+ shader.destroy();
72
+ return;
73
+ }
74
+
46
75
  const key = this._hashShader(shader);
47
76
  const cacheEntry = this._cache[key];
48
77
  if (cacheEntry) {
@@ -51,14 +80,21 @@ export class ShaderFactory {
51
80
  if (this.destroyPolicy === 'unused') {
52
81
  delete this._cache[key];
53
82
  cacheEntry.shader.destroy();
83
+ if (this.debug) {
84
+ log.warn(`${this}: Releasing shader ${shader.id}, destroyed`)();
85
+ }
54
86
  }
87
+ } else if (cacheEntry.useCount < 0) {
88
+ throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
89
+ } else if (this.debug) {
90
+ log.warn(`${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
55
91
  }
56
92
  }
57
93
  }
58
94
 
59
95
  // PRIVATE
60
96
 
61
- private _hashShader(value: Shader | ShaderProps): string {
97
+ protected _hashShader(value: Shader | ShaderProps): string {
62
98
  return `${value.stage}:${value.source}`;
63
99
  }
64
100
  }
@@ -86,9 +86,9 @@ export class Geometry {
86
86
  }
87
87
  }
88
88
 
89
- if (this.indices && this.indices.isIndexed !== undefined) {
89
+ if (this.indices && this.indices['isIndexed'] !== undefined) {
90
90
  this.indices = Object.assign({}, this.indices);
91
- delete this.indices.isIndexed;
91
+ delete this.indices['isIndexed'];
92
92
  }
93
93
 
94
94
  this.vertexCount = vertexCount || this._calculateVertexCount(this.attributes, this.indices);
@@ -103,6 +103,7 @@ export class Geometry {
103
103
  * TODO Geometry types are a mess
104
104
  */
105
105
  getAttributes(): GeometryAttributes {
106
+ // @ts-ignore
106
107
  return this.indices ? {indices: this.indices, ...this.attributes} : this.attributes;
107
108
  }
108
109
 
package/src/index.ts CHANGED
@@ -80,6 +80,18 @@ export {SwapFramebuffers} from './compute/swap';
80
80
  export type {ComputationProps} from './compute/computation';
81
81
  export {Computation} from './compute/computation';
82
82
 
83
+ export type {
84
+ TextureCubeFace,
85
+ TextureImageData,
86
+ TextureData,
87
+ Texture1DData,
88
+ Texture2DData,
89
+ Texture3DData,
90
+ TextureCubeData,
91
+ TextureArrayData,
92
+ TextureCubeArrayData
93
+ } from './async-texture/async-texture';
94
+
83
95
  export type {AsyncTextureProps} from './async-texture/async-texture';
84
96
  export {AsyncTexture} from './async-texture/async-texture';
85
97
 
@@ -13,7 +13,6 @@ import type {
13
13
  TransformFeedback,
14
14
  AttributeInfo,
15
15
  Binding,
16
- UniformValue,
17
16
  PrimitiveTopology
18
17
  } from '@luma.gl/core';
19
18
  import {
@@ -27,10 +26,8 @@ import {
27
26
  RenderPass,
28
27
  UniformStore,
29
28
  log,
30
- getTypedArrayFromDataType,
31
- getAttributeInfosFromLayouts,
32
- _BufferLayoutHelper,
33
- sortedBufferLayoutByShaderSourceLocations
29
+ getTypedArrayConstructor,
30
+ getAttributeInfosFromLayouts
34
31
  } from '@luma.gl/core';
35
32
 
36
33
  import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
@@ -43,25 +40,24 @@ import {ShaderFactory} from '../factories/shader-factory';
43
40
  import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
44
41
  import {debugFramebuffer} from '../debug/debug-framebuffer';
45
42
  import {deepEqual} from '../utils/deep-equal';
43
+ import {BufferLayoutHelper} from '../utils/buffer-layout-helper';
44
+ import {sortedBufferLayoutByShaderSourceLocations} from '../utils/buffer-layout-order';
46
45
  import {uid} from '../utils/uid';
47
46
  import {ShaderInputs} from '../shader-inputs';
48
- // import type {AsyncTextureProps} from '../async-texture/async-texture';
49
47
  import {AsyncTexture} from '../async-texture/async-texture';
50
48
 
51
- import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
52
-
53
49
  const LOG_DRAW_PRIORITY = 2;
54
50
  const LOG_DRAW_TIMEOUT = 10000;
55
51
 
56
52
  export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
57
53
  source?: string;
58
- vs: string | null;
59
- fs: string | null;
54
+ vs?: string | null;
55
+ fs?: string | null;
60
56
 
61
57
  /** shadertool shader modules (added to shader code) */
62
58
  modules?: ShaderModule[];
63
59
  /** Shadertool module defines (configures shader code)*/
64
- defines?: Record<string, string | number | boolean>;
60
+ defines?: Record<string, boolean>;
65
61
  // TODO - injections, hooks etc?
66
62
 
67
63
  /** Shader inputs, used to generated uniform buffers and bindings */
@@ -95,9 +91,6 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
95
91
 
96
92
  transformFeedback?: TransformFeedback;
97
93
 
98
- /** Mapped uniforms for shadertool modules */
99
- moduleSettings?: Record<string, Record<string, any>>;
100
-
101
94
  /** Show shader source in browser? */
102
95
  debugShaders?: 'never' | 'errors' | 'warnings' | 'always';
103
96
 
@@ -128,7 +121,6 @@ export class Model {
128
121
  userData: {},
129
122
  defines: {},
130
123
  modules: [],
131
- moduleSettings: undefined!,
132
124
  geometry: null,
133
125
  indexBuffer: null,
134
126
  attributes: {},
@@ -188,8 +180,6 @@ export class Model {
188
180
  constantAttributes: Record<string, TypedArray> = {};
189
181
  /** Bindings (textures, samplers, uniform buffers) */
190
182
  bindings: Record<string, Binding | AsyncTexture> = {};
191
- /** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/
192
- uniforms: Record<string, UniformValue> = {};
193
183
 
194
184
  /**
195
185
  * VertexArray
@@ -212,7 +202,6 @@ export class Model {
212
202
 
213
203
  _attributeInfos: Record<string, AttributeInfo> = {};
214
204
  _gpuGeometry: GPUGeometry | null = null;
215
- private _getModuleUniforms: (props?: Record<string, Record<string, any>>) => Record<string, any>;
216
205
  private props: Required<ModelProps>;
217
206
 
218
207
  _pipelineNeedsUpdate: string | false = 'newly created';
@@ -309,7 +298,8 @@ export class Model {
309
298
  this.pipeline = this._updatePipeline();
310
299
 
311
300
  this.vertexArray = device.createVertexArray({
312
- renderPipeline: this.pipeline
301
+ shaderLayout: this.pipeline.shaderLayout,
302
+ bufferLayout: this.pipeline.bufferLayout
313
303
  });
314
304
 
315
305
  // Now we can apply geometry attributes
@@ -340,13 +330,6 @@ export class Model {
340
330
  if (props.bindings) {
341
331
  this.setBindings(props.bindings);
342
332
  }
343
- if (props.uniforms) {
344
- this.setUniformsWebGL(props.uniforms);
345
- }
346
- if (props.moduleSettings) {
347
- // log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
348
- this.updateModuleSettingsWebGL(props.moduleSettings);
349
- }
350
333
  if (props.transformFeedback) {
351
334
  this.transformFeedback = props.transformFeedback;
352
335
  }
@@ -356,16 +339,19 @@ export class Model {
356
339
  }
357
340
 
358
341
  destroy(): void {
359
- if (this._destroyed) return;
360
- this.pipelineFactory.release(this.pipeline);
361
- this.shaderFactory.release(this.pipeline.vs);
362
- if (this.pipeline.fs) {
363
- this.shaderFactory.release(this.pipeline.fs);
364
- }
365
- this._uniformStore.destroy();
366
- // TODO - mark resource as managed and destroyIfManaged() ?
367
- this._gpuGeometry?.destroy();
368
- this._destroyed = true;
342
+ if (!this._destroyed) {
343
+ // Release pipeline before we destroy the shaders used by the pipeline
344
+ this.pipelineFactory.release(this.pipeline);
345
+ // Release the shaders
346
+ this.shaderFactory.release(this.pipeline.vs);
347
+ if (this.pipeline.fs) {
348
+ this.shaderFactory.release(this.pipeline.fs);
349
+ }
350
+ this._uniformStore.destroy();
351
+ // TODO - mark resource as managed and destroyIfManaged() ?
352
+ this._gpuGeometry?.destroy();
353
+ this._destroyed = true;
354
+ }
369
355
  }
370
356
 
371
357
  // Draw call
@@ -425,9 +411,6 @@ export class Model {
425
411
  this.pipeline.setBindings(syncBindings, {
426
412
  disableWarnings: this.props.disableWarnings
427
413
  });
428
- if (!isObjectEmpty(this.uniforms)) {
429
- this.pipeline.setUniformsWebGL(this.uniforms);
430
- }
431
414
 
432
415
  const {indexBuffer} = this.vertexArray;
433
416
  const indexCount = indexBuffer
@@ -476,7 +459,7 @@ export class Model {
476
459
  const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
477
460
  if (gpuGeometry) {
478
461
  this.setTopology(gpuGeometry.topology || 'triangle-list');
479
- const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
462
+ const bufferLayoutHelper = new BufferLayoutHelper(this.bufferLayout);
480
463
  this.bufferLayout = bufferLayoutHelper.mergeBufferLayouts(
481
464
  gpuGeometry.bufferLayout,
482
465
  this.bufferLayout
@@ -504,7 +487,7 @@ export class Model {
504
487
  * @note Triggers a pipeline rebuild / pipeline cache fetch
505
488
  */
506
489
  setBufferLayout(bufferLayout: BufferLayout[]): void {
507
- const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
490
+ const bufferLayoutHelper = new BufferLayoutHelper(this.bufferLayout);
508
491
  this.bufferLayout = this._gpuGeometry
509
492
  ? bufferLayoutHelper.mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
510
493
  : bufferLayout;
@@ -516,7 +499,8 @@ export class Model {
516
499
  // vertex array needs to be updated if we update buffer layout,
517
500
  // but not if we update parameters
518
501
  this.vertexArray = this.device.createVertexArray({
519
- renderPipeline: this.pipeline
502
+ shaderLayout: this.pipeline.shaderLayout,
503
+ bufferLayout: this.pipeline.bufferLayout
520
504
  });
521
505
 
522
506
  // Reapply geometry attributes to the new vertex array
@@ -615,7 +599,7 @@ export class Model {
615
599
  */
616
600
  setAttributes(buffers: Record<string, Buffer>, options?: {disableWarnings?: boolean}): void {
617
601
  const disableWarnings = options?.disableWarnings ?? this.props.disableWarnings;
618
- if (buffers.indices) {
602
+ if (buffers['indices']) {
619
603
  log.warn(
620
604
  `Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`
621
605
  )();
@@ -627,7 +611,7 @@ export class Model {
627
611
  this.pipeline.shaderLayout,
628
612
  this.bufferLayout
629
613
  );
630
- const bufferLayoutHelper = new _BufferLayoutHelper(this.bufferLayout);
614
+ const bufferLayoutHelper = new BufferLayoutHelper(this.bufferLayout);
631
615
 
632
616
  // Check if all buffers have a layout
633
617
  for (const [bufferName, buffer] of Object.entries(buffers)) {
@@ -689,42 +673,7 @@ export class Model {
689
673
  this.setNeedsRedraw('constants');
690
674
  }
691
675
 
692
- // DEPRECATED METHODS
693
-
694
- /**
695
- * Sets individual uniforms
696
- * @deprecated WebGL only, use uniform buffers for portability
697
- * @param uniforms
698
- */
699
- setUniforms(uniforms: Record<string, UniformValue>): void {
700
- this.setUniformsWebGL(uniforms);
701
- }
702
-
703
- /**
704
- * Sets individual uniforms
705
- * @deprecated WebGL only, use uniform buffers for portability
706
- * @param uniforms
707
- */
708
- setUniformsWebGL(uniforms: Record<string, UniformValue>): void {
709
- if (!isObjectEmpty(uniforms)) {
710
- this.pipeline.setUniformsWebGL(uniforms);
711
- Object.assign(this.uniforms, uniforms);
712
- }
713
- this.setNeedsRedraw('uniforms');
714
- }
715
-
716
- /**
717
- * @deprecated Updates shader module settings (which results in uniforms being set)
718
- */
719
- updateModuleSettingsWebGL(props: Record<string, any>): void {
720
- // log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
721
- const {bindings, uniforms} = splitUniformsAndBindings(this._getModuleUniforms(props));
722
- Object.assign(this.bindings, bindings);
723
- Object.assign(this.uniforms, uniforms);
724
- this.setNeedsRedraw('moduleSettings');
725
- }
726
-
727
- // Internal methods
676
+ // INTERNAL METHODS
728
677
 
729
678
  /** Check that bindings are loaded. Returns id of first binding that is still loading. */
730
679
  _areBindingsLoading(): string | false {
@@ -890,10 +839,6 @@ export class Model {
890
839
  log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
891
840
 
892
841
  const uniformTable = this.shaderInputs.getDebugTable();
893
- // Add any global uniforms
894
- for (const [name, value] of Object.entries(this.uniforms)) {
895
- uniformTable[name] = {value};
896
- }
897
842
  log.table(LOG_DRAW_PRIORITY, uniformTable)();
898
843
 
899
844
  const attributeTable = this._getAttributeDebugTable();
@@ -940,7 +885,7 @@ export class Model {
940
885
  indexBuffer.indexType === 'uint32'
941
886
  ? new Uint32Array(indexBuffer.debugData)
942
887
  : new Uint16Array(indexBuffer.debugData);
943
- table.indices = {
888
+ table['indices'] = {
944
889
  name: 'indices',
945
890
  type: indexBuffer.indexType,
946
891
  values: values.toString()
@@ -951,7 +896,7 @@ export class Model {
951
896
 
952
897
  // TODO - fix typing of luma data types
953
898
  _getBufferOrConstantValues(attribute: Buffer | TypedArray, dataType: any): string {
954
- const TypedArrayConstructor = getTypedArrayFromDataType(dataType);
899
+ const TypedArrayConstructor = getTypedArrayConstructor(dataType);
955
900
  const typedArray =
956
901
  attribute instanceof Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
957
902
  return typedArray.toString();
@@ -11,7 +11,7 @@ const BACKGROUND_FS_WGSL = /* wgsl */ `\
11
11
  @group(0) @binding(1) var backgroundTextureSampler: sampler;
12
12
 
13
13
  fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
14
- let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0) * 2;
14
+ let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0);
15
15
  let texSize: vec2<f32> = vec2<f32>(f32(iTexSize.x), f32(iTexSize.y));
16
16
  var position: vec2<f32> = coordinates.xy / texSize;
17
17
  return position;
@@ -32,7 +32,7 @@ uniform sampler2D backgroundTexture;
32
32
  out vec4 fragColor;
33
33
 
34
34
  vec2 billboardTexture_getTextureUV() {
35
- ivec2 iTexSize = textureDimensions(backgroundTexture, 0) * 2;
35
+ ivec2 iTexSize = textureSize(backgroundTexture, 0);
36
36
  vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
37
37
  vec2 position = gl_FragCoord.xy / texSize;
38
38
  return position;
@@ -67,14 +67,13 @@ export class BackgroundTextureModel extends ClipSpace {
67
67
  fs: BACKGROUND_FS,
68
68
  parameters: {
69
69
  depthWriteEnabled: false,
70
- depthCompare: 'always',
71
70
  ...(props.blend
72
71
  ? {
73
72
  blend: true,
74
73
  blendColorOperation: 'add',
75
74
  blendAlphaOperation: 'add',
76
75
  blendColorSrcFactor: 'one',
77
- blendColorDstFactor: 'one-minus-src-color',
76
+ blendColorDstFactor: 'one-minus-src',
78
77
  blendAlphaSrcFactor: 'one',
79
78
  blendAlphaDstFactor: 'one-minus-src-alpha'
80
79
  }
@@ -82,6 +81,9 @@ export class BackgroundTextureModel extends ClipSpace {
82
81
  }
83
82
  });
84
83
 
84
+ if (!props.backgroundTexture) {
85
+ throw new Error('BackgroundTextureModel requires a backgroundTexture prop');
86
+ }
85
87
  this.setTexture(props.backgroundTexture);
86
88
  }
87
89
 
@@ -42,7 +42,7 @@ export class LegacyPickingManager {
42
42
  /** Prepare for rendering picking colors */
43
43
  beginRenderPass() {
44
44
  const framebuffer = this.getFramebuffer();
45
- framebuffer.resize(this.device.getCanvasContext().getPixelSize());
45
+ framebuffer.resize(this.device.getCanvasContext().getDevicePixelSize());
46
46
 
47
47
  this.shaderInputs.setProps({picking: {isActive: true}});
48
48
 
@@ -90,7 +90,7 @@ export class LegacyPickingManager {
90
90
  * Get pick position in device pixel range
91
91
  * use the center pixel location in device pixel range
92
92
  */
93
- getPickPosition(mousePosition: number[]): [number, number] {
93
+ getPickPosition(mousePosition: [number, number]): [number, number] {
94
94
  const devicePixels = this.device.getCanvasContext().cssToDevicePixels(mousePosition);
95
95
  const pickX = devicePixels.x + Math.floor(devicePixels.width / 2);
96
96
  const pickY = devicePixels.y + Math.floor(devicePixels.height / 2);
@@ -67,7 +67,7 @@ export class PickingManager {
67
67
  /** Prepare for rendering picking colors */
68
68
  beginRenderPass() {
69
69
  const framebuffer = this.getFramebuffer();
70
- framebuffer.resize(this.device.getDefaultCanvasContext().getPixelSize());
70
+ framebuffer.resize(this.device.getDefaultCanvasContext().getDevicePixelSize());
71
71
 
72
72
  this.props.shaderInputs?.setProps({picking: {isActive: true}});
73
73
 
@@ -80,7 +80,7 @@ export class PickingManager {
80
80
  return pickingPass;
81
81
  }
82
82
 
83
- getPickInfo(mousePosition: [number, number]): PickInfo | null {
83
+ async updatePickInfo(mousePosition: [number, number]): Promise<PickInfo | null> {
84
84
  const framebuffer = this.getFramebuffer();
85
85
 
86
86
  // use the center pixel location in device pixel range
@@ -128,7 +128,7 @@ export class PickingManager {
128
128
  * Get pick position in device pixel range
129
129
  * use the center pixel location in device pixel range
130
130
  */
131
- getPickPosition(mousePosition: number[]): [number, number] {
131
+ getPickPosition(mousePosition: [number, number]): [number, number] {
132
132
  const devicePixels = this.device.getDefaultCanvasContext().cssToDevicePixels(mousePosition);
133
133
  const pickX = devicePixels.x + Math.floor(devicePixels.width / 2);
134
134
  const pickY = devicePixels.y + Math.floor(devicePixels.height / 2);
@@ -37,11 +37,11 @@ export function getFragmentShaderForRenderPass(options: {
37
37
  function getFilterShaderWGSL(func: string) {
38
38
  return /* wgsl */ `\
39
39
  // Binding 0:1 is reserved for shader passes
40
- @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
40
+ // @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
41
41
  @group(0) @binding(1) var texture: texture_2d<f32>;
42
42
  @group(0) @binding(2) var sampler: sampler;
43
43
 
44
- struct FragmentInputs = {
44
+ struct FragmentInputs {
45
45
  @location(0) fragUV: vec2f,
46
46
  @location(1) fragPosition: vec4f,
47
47
  @location(2) fragCoordinate: vec4f
@@ -44,9 +44,9 @@ export class ShaderPassRenderer {
44
44
  );
45
45
  this.shaderInputs = props.shaderInputs || new ShaderInputs(modules);
46
46
 
47
- const size = device.getCanvasContext().getPixelSize();
47
+ const size = device.getCanvasContext().getDrawingBufferSize();
48
48
  this.swapFramebuffers = new SwapFramebuffers(device, {
49
- colorAttachments: ['rgba8unorm'],
49
+ colorAttachments: [device.preferredColorFormat],
50
50
  width: size[0],
51
51
  height: size[1]
52
52
  });
@@ -99,7 +99,7 @@ void main() {
99
99
  // this.props.passes.forEach(pass => pass.resize(width, height));
100
100
  }
101
101
 
102
- renderToScreen(options: {sourceTexture: AsyncTexture; uniforms: any; bindings: any}): boolean {
102
+ renderToScreen(options: {sourceTexture: AsyncTexture; uniforms?: any; bindings?: any}): boolean {
103
103
  // Run the shader passes and generate an output texture
104
104
  const outputTexture = this.renderToTexture(options);
105
105
  if (!outputTexture) {
@@ -107,7 +107,16 @@ void main() {
107
107
  return false;
108
108
  }
109
109
 
110
- const renderPass = this.device.beginRenderPass({clearColor: [0, 0, 0, 1], clearDepth: 1});
110
+ const framebuffer = this.device
111
+ .getDefaultCanvasContext()
112
+ // @ts-expect-error TODO - remove after republish
113
+ .getCurrentFramebuffer({depthStencilAttachment: false});
114
+ const renderPass = this.device.beginRenderPass({
115
+ id: 'shader-pass-renderer-to-screen',
116
+ framebuffer,
117
+ clearColor: [0, 0, 0, 1],
118
+ clearDepth: 1
119
+ });
111
120
  this.clipSpace.setBindings({sourceTexture: outputTexture});
112
121
  this.clipSpace.draw(renderPass);
113
122
  renderPass.end();
@@ -119,8 +128,8 @@ void main() {
119
128
  */
120
129
  renderToTexture(options: {
121
130
  sourceTexture: AsyncTexture;
122
- uniforms: any;
123
- bindings: any;
131
+ uniforms?: any;
132
+ bindings?: any;
124
133
  }): Texture | null {
125
134
  const {sourceTexture} = options;
126
135
  if (!sourceTexture.isReady) {
@@ -134,6 +143,7 @@ void main() {
134
143
 
135
144
  // Clear the current texture before we begin
136
145
  const clearTexturePass = this.device.beginRenderPass({
146
+ id: 'shader-pass-renderer-clear-texture',
137
147
  framebuffer: this.swapFramebuffers.current,
138
148
  clearColor: [0, 0, 0, 1]
139
149
  });
@@ -163,6 +173,7 @@ void main() {
163
173
  };
164
174
 
165
175
  const renderPass = this.device.beginRenderPass({
176
+ id: 'shader-pass-renderer-run-pass',
166
177
  framebuffer: this.swapFramebuffers.next,
167
178
  clearColor: [0, 0, 0, 1],
168
179
  clearDepth: 1
@@ -226,8 +237,7 @@ class SubPassRenderer {
226
237
  fs,
227
238
  modules: [shaderPass],
228
239
  parameters: {
229
- depthWriteEnabled: false,
230
- depthCompare: 'always'
240
+ depthWriteEnabled: false
231
241
  }
232
242
  });
233
243
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  import type {Binding, UniformValue} from '@luma.gl/core';
6
6
  import {log} from '@luma.gl/core';
7
- // import type {ShaderUniformType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core';
7
+ // import type {VariableShaderType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core';
8
8
  import {getShaderModuleDependencies, ShaderModule} from '@luma.gl/shadertools';
9
9
  import {splitUniformsAndBindings} from './model/split-uniforms-and-bindings';
10
10
 
@@ -0,0 +1,51 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {log, type BufferLayout} from '@luma.gl/core';
6
+
7
+ /** BufferLayoutHelper is a helper class that should not be used directly by applications */
8
+ export class BufferLayoutHelper {
9
+ bufferLayouts: BufferLayout[];
10
+
11
+ constructor(bufferLayouts: BufferLayout[]) {
12
+ this.bufferLayouts = bufferLayouts;
13
+ }
14
+
15
+ getBufferLayout(name: string): BufferLayout | null {
16
+ return this.bufferLayouts.find(layout => layout.name === name) || null;
17
+ }
18
+
19
+ /** Get attribute names from a BufferLayout */
20
+ getAttributeNamesForBuffer(bufferLayout: BufferLayout): string[] {
21
+ return bufferLayout.attributes
22
+ ? bufferLayout.attributes?.map(layout => layout.attribute)
23
+ : [bufferLayout.name];
24
+ }
25
+
26
+ mergeBufferLayouts(
27
+ bufferLayouts1: BufferLayout[],
28
+ bufferLayouts2: BufferLayout[]
29
+ ): BufferLayout[] {
30
+ const mergedLayouts = [...bufferLayouts1];
31
+ for (const attribute of bufferLayouts2) {
32
+ const index = mergedLayouts.findIndex(attribute2 => attribute2.name === attribute.name);
33
+ if (index < 0) {
34
+ mergedLayouts.push(attribute);
35
+ } else {
36
+ mergedLayouts[index] = attribute;
37
+ }
38
+ }
39
+ return mergedLayouts;
40
+ }
41
+
42
+ getBufferIndex(bufferName: string): number {
43
+ const bufferIndex = this.bufferLayouts.findIndex(layout => layout.name === bufferName);
44
+
45
+ if (bufferIndex === -1) {
46
+ log.warn(`BufferLayout: Missing buffer for "${bufferName}".`)();
47
+ }
48
+
49
+ return bufferIndex;
50
+ }
51
+ }
@@ -0,0 +1,26 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {type BufferLayout, type ShaderLayout} from '@luma.gl/core';
6
+
7
+ export function sortedBufferLayoutByShaderSourceLocations(
8
+ shaderLayout: ShaderLayout,
9
+ bufferLayout: BufferLayout[]
10
+ ): BufferLayout[] {
11
+ const shaderLayoutMap = Object.fromEntries(
12
+ shaderLayout.attributes.map(attr => [attr.name, attr.location])
13
+ );
14
+
15
+ const sortedLayout = bufferLayout.slice();
16
+ sortedLayout.sort((a, b) => {
17
+ const attributeNamesA = a.attributes ? a.attributes.map(attr => attr.attribute) : [a.name];
18
+ const attributeNamesB = b.attributes ? b.attributes.map(attr => attr.attribute) : [b.name];
19
+ const minLocationA = Math.min(...attributeNamesA.map(name => shaderLayoutMap[name]));
20
+ const minLocationB = Math.min(...attributeNamesB.map(name => shaderLayoutMap[name]));
21
+
22
+ return minLocationA - minLocationB;
23
+ });
24
+
25
+ return sortedLayout;
26
+ }