@luma.gl/engine 9.3.0-alpha.9 → 9.3.1

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 (63) hide show
  1. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  2. package/dist/animation-loop/make-animation-loop.js +1 -0
  3. package/dist/animation-loop/make-animation-loop.js.map +1 -1
  4. package/dist/compute/computation.js +2 -2
  5. package/dist/compute/computation.js.map +1 -1
  6. package/dist/debug/debug-framebuffer.d.ts +9 -4
  7. package/dist/debug/debug-framebuffer.d.ts.map +1 -1
  8. package/dist/debug/debug-framebuffer.js +91 -45
  9. package/dist/debug/debug-framebuffer.js.map +1 -1
  10. package/dist/dist.dev.js +200 -126
  11. package/dist/dist.min.js +33 -33
  12. package/dist/dynamic-texture/dynamic-texture.d.ts.map +1 -1
  13. package/dist/dynamic-texture/dynamic-texture.js +3 -1
  14. package/dist/dynamic-texture/dynamic-texture.js.map +1 -1
  15. package/dist/dynamic-texture/texture-data.js +2 -2
  16. package/dist/dynamic-texture/texture-data.js.map +1 -1
  17. package/dist/geometries/cube-geometry.js +7 -7
  18. package/dist/geometries/cube-geometry.js.map +1 -1
  19. package/dist/geometries/ico-sphere-geometry.js +3 -1
  20. package/dist/geometries/ico-sphere-geometry.js.map +1 -1
  21. package/dist/geometry/gpu-geometry.d.ts.map +1 -1
  22. package/dist/geometry/gpu-geometry.js +3 -0
  23. package/dist/geometry/gpu-geometry.js.map +1 -1
  24. package/dist/index.cjs +176 -108
  25. package/dist/index.cjs.map +3 -3
  26. package/dist/material/material.js +2 -2
  27. package/dist/material/material.js.map +1 -1
  28. package/dist/model/model.d.ts.map +1 -1
  29. package/dist/model/model.js +45 -34
  30. package/dist/model/model.js.map +1 -1
  31. package/dist/models/billboard-texture-model.js +4 -4
  32. package/dist/models/billboard-texture-module.d.ts +1 -1
  33. package/dist/models/billboard-texture-module.js +1 -1
  34. package/dist/models/light-model-utils.js +2 -2
  35. package/dist/modules/picking/color-picking.d.ts +2 -2
  36. package/dist/modules/picking/index-picking.d.ts +2 -2
  37. package/dist/modules/picking/legacy-color-picking.d.ts +4 -4
  38. package/dist/modules/picking/picking-uniforms.d.ts +1 -1
  39. package/dist/modules/picking/picking-uniforms.d.ts.map +1 -1
  40. package/dist/modules/picking/picking-uniforms.js +1 -1
  41. package/dist/modules/picking/picking.d.ts +2 -2
  42. package/dist/passes/get-fragment-shader.js +4 -4
  43. package/dist/shader-inputs.d.ts.map +1 -1
  44. package/dist/shader-inputs.js +20 -23
  45. package/dist/shader-inputs.js.map +1 -1
  46. package/package.json +4 -4
  47. package/src/animation-loop/make-animation-loop.ts +1 -0
  48. package/src/compute/computation.ts +2 -2
  49. package/src/debug/debug-framebuffer.ts +139 -61
  50. package/src/dynamic-texture/dynamic-texture.ts +3 -5
  51. package/src/dynamic-texture/texture-data.ts +2 -2
  52. package/src/dynamic-texture/texture-data.ts.disabled +1 -1
  53. package/src/geometries/cube-geometry.ts +7 -7
  54. package/src/geometries/ico-sphere-geometry.ts +3 -1
  55. package/src/geometry/gpu-geometry.ts +3 -0
  56. package/src/material/material.ts +2 -2
  57. package/src/model/model.ts +48 -36
  58. package/src/models/billboard-texture-model.ts +4 -4
  59. package/src/models/billboard-texture-module.ts +1 -1
  60. package/src/models/light-model-utils.ts +2 -2
  61. package/src/modules/picking/picking-uniforms.ts +1 -1
  62. package/src/passes/get-fragment-shader.ts +4 -4
  63. package/src/shader-inputs.ts +32 -41
@@ -53,6 +53,7 @@ import {Material} from '../material/material';
53
53
 
54
54
  const LOG_DRAW_PRIORITY = 2;
55
55
  const LOG_DRAW_TIMEOUT = 10000;
56
+ const PIPELINE_INITIALIZATION_FAILED = 'render pipeline initialization failed';
56
57
 
57
58
  export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
58
59
  source?: string;
@@ -445,6 +446,7 @@ export class Model {
445
446
  }
446
447
 
447
448
  let drawSuccess: boolean;
449
+ let pipelineErrored = this.pipeline.isErrored;
448
450
  try {
449
451
  renderPass.pushDebugGroup(`${this}.draw(${renderPass})`);
450
452
  this._logDrawCallStart();
@@ -453,36 +455,45 @@ export class Model {
453
455
  // TODO - inside RenderPass is likely the worst place to do this from performance perspective.
454
456
  // Application can call Model.predraw() to avoid this.
455
457
  this.pipeline = this._updatePipeline();
458
+ pipelineErrored = this.pipeline.isErrored;
456
459
 
457
- const syncBindings = this._getBindings();
458
- const syncBindGroups = this._getBindGroups();
459
-
460
- const {indexBuffer} = this.vertexArray;
461
- const indexCount = indexBuffer
462
- ? indexBuffer.byteLength / (indexBuffer.indexType === 'uint32' ? 4 : 2)
463
- : undefined;
464
-
465
- drawSuccess = this.pipeline.draw({
466
- renderPass,
467
- vertexArray: this.vertexArray,
468
- isInstanced: this.isInstanced,
469
- vertexCount: this.vertexCount,
470
- instanceCount: this.instanceCount,
471
- indexCount,
472
- transformFeedback: this.transformFeedback || undefined,
473
- // Pipelines may be shared across models when caching is enabled, so bindings
474
- // and WebGL uniforms must be supplied on every draw instead of being stored
475
- // on the pipeline instance.
476
- bindings: syncBindings,
477
- bindGroups: syncBindGroups,
478
- _bindGroupCacheKeys: this._getBindGroupCacheKeys(),
479
- uniforms: this.props.uniforms,
480
- // WebGL shares underlying cached pipelines even for models that have different parameters and topology,
481
- // so we must provide our unique parameters to each draw
482
- // (In WebGPU most parameters are encoded in the pipeline and cannot be changed per draw call)
483
- parameters: this.parameters,
484
- topology: this.topology
485
- });
460
+ if (pipelineErrored) {
461
+ log.info(
462
+ LOG_DRAW_PRIORITY,
463
+ `>>> DRAWING ABORTED ${this.id}: ${PIPELINE_INITIALIZATION_FAILED}`
464
+ )();
465
+ drawSuccess = false;
466
+ } else {
467
+ const syncBindings = this._getBindings();
468
+ const syncBindGroups = this._getBindGroups();
469
+
470
+ const {indexBuffer} = this.vertexArray;
471
+ const indexCount = indexBuffer
472
+ ? indexBuffer.byteLength / (indexBuffer.indexType === 'uint32' ? 4 : 2)
473
+ : undefined;
474
+
475
+ drawSuccess = this.pipeline.draw({
476
+ renderPass,
477
+ vertexArray: this.vertexArray,
478
+ isInstanced: this.isInstanced,
479
+ vertexCount: this.vertexCount,
480
+ instanceCount: this.instanceCount,
481
+ indexCount,
482
+ transformFeedback: this.transformFeedback || undefined,
483
+ // Pipelines may be shared across models when caching is enabled, so bindings
484
+ // and WebGL uniforms must be supplied on every draw instead of being stored
485
+ // on the pipeline instance.
486
+ bindings: syncBindings,
487
+ bindGroups: syncBindGroups,
488
+ _bindGroupCacheKeys: this._getBindGroupCacheKeys(),
489
+ uniforms: this.props.uniforms,
490
+ // WebGL shares underlying cached pipelines even for models that have different parameters and topology,
491
+ // so we must provide our unique parameters to each draw
492
+ // (In WebGPU most parameters are encoded in the pipeline and cannot be changed per draw call)
493
+ parameters: this.parameters,
494
+ topology: this.topology
495
+ });
496
+ }
486
497
  } finally {
487
498
  renderPass.popDebugGroup();
488
499
  this._logDrawCallEnd();
@@ -493,6 +504,8 @@ export class Model {
493
504
  if (drawSuccess) {
494
505
  this._lastDrawTimestamp = this.device.timestamp;
495
506
  this._needsRedraw = false;
507
+ } else if (pipelineErrored) {
508
+ this._needsRedraw = PIPELINE_INITIALIZATION_FAILED;
496
509
  } else {
497
510
  this._needsRedraw = 'waiting for resource initialization';
498
511
  }
@@ -601,11 +614,11 @@ export class Model {
601
614
  /** Set the shader inputs */
602
615
  setShaderInputs(shaderInputs: ShaderInputs): void {
603
616
  this.shaderInputs = shaderInputs;
604
- this._uniformStore = new UniformStore(this.shaderInputs.modules);
617
+ this._uniformStore = new UniformStore(this.device, this.shaderInputs.modules);
605
618
  // Create uniform buffer bindings for all modules that actually have uniforms
606
619
  for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
607
620
  if (shaderModuleHasUniforms(module) && !this.material?.ownsModule(moduleName)) {
608
- const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
621
+ const uniformBuffer = this._uniformStore.getManagedUniformBuffer(moduleName);
609
622
  this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
610
623
  }
611
624
  }
@@ -948,12 +961,11 @@ export class Model {
948
961
  // } || (this._drawCount++ > 3 && this._drawCount % 60)) {
949
962
  return;
950
963
  }
951
- // TODO - display framebuffer output in debug window
952
964
  const framebuffer = renderPass.props.framebuffer;
953
- if (framebuffer) {
954
- debugFramebuffer(framebuffer, {id: framebuffer.id, minimap: true});
955
- // log.image({logLevel: LOG_DRAW_PRIORITY, message: `${framebuffer.id} %c sup?`, image})();
956
- }
965
+ debugFramebuffer(renderPass, framebuffer, {
966
+ id: framebuffer?.id || `${this.id}-framebuffer`,
967
+ minimap: true
968
+ });
957
969
  }
958
970
 
959
971
  _getAttributeDebugTable(): Record<string, Record<string, unknown>> {
@@ -15,12 +15,12 @@ const backgroundModule = {
15
15
  } as const satisfies ShaderModule<{}, {scale: [number, number]}>;
16
16
 
17
17
  const BACKGROUND_FS_WGSL = /* wgsl */ `\
18
- @group(0) @binding(0) var backgroundTexture: texture_2d<f32>;
19
- @group(0) @binding(1) var backgroundTextureSampler: sampler;
18
+ @group(0) @binding(auto) var backgroundTexture: texture_2d<f32>;
19
+ @group(0) @binding(auto) var backgroundTextureSampler: sampler;
20
20
  struct backgroundUniforms {
21
21
  scale: vec2<f32>,
22
22
  };
23
- @group(0) @binding(2) var<uniform> background: backgroundUniforms;
23
+ @group(0) @binding(auto) var<uniform> background: backgroundUniforms;
24
24
 
25
25
  fn billboardTexture_getTextureUV(uv: vec2<f32>) -> vec2<f32> {
26
26
  let scale: vec2<f32> = background.scale;
@@ -41,7 +41,7 @@ precision highp float;
41
41
 
42
42
  uniform sampler2D backgroundTexture;
43
43
 
44
- uniform backgroundUniforms {
44
+ layout(std140) uniform backgroundUniforms {
45
45
  vec2 scale;
46
46
  } background;
47
47
 
@@ -7,7 +7,7 @@ import {ShaderModule} from '@luma.gl/shadertools';
7
7
  const BACKGROUND_FS = /* glsl */ `\
8
8
  #version 300 es
9
9
 
10
- uniform billboardTextureUniforms {
10
+ layout(std140) uniform billboardTextureUniforms {
11
11
  vec2 topLeft;
12
12
  vec2 bottomRight;
13
13
  } billboardTexture;
@@ -496,7 +496,7 @@ struct lightMarkerUniforms {
496
496
  viewProjectionMatrix: mat4x4<f32>,
497
497
  };
498
498
 
499
- @binding(0) @group(0) var<uniform> lightMarker : lightMarkerUniforms;
499
+ @group(0) @binding(auto) var<uniform> lightMarker : lightMarkerUniforms;
500
500
 
501
501
  struct VertexInputs {
502
502
  @location(0) positions : vec3<f32>,
@@ -547,7 +547,7 @@ in vec3 instanceDirection;
547
547
  in vec3 instanceScale;
548
548
  in vec4 instanceColor;
549
549
 
550
- uniform lightMarkerUniforms {
550
+ layout(std140) uniform lightMarkerUniforms {
551
551
  mat4 viewProjectionMatrix;
552
552
  } lightMarker;
553
553
 
@@ -78,7 +78,7 @@ export const GLSL_UNIFORMS = /* glsl */ `\
78
78
  precision highp float;
79
79
  precision highp int;
80
80
 
81
- uniform pickingUniforms {
81
+ layout(std140) uniform pickingUniforms {
82
82
  int isActive;
83
83
  int indexMode;
84
84
  int batchIndex;
@@ -36,8 +36,8 @@ export function getFragmentShaderForRenderPass(options: {
36
36
  /** Get a filtering WGSL fragment shader */
37
37
  function getFilterShaderWGSL(func: string) {
38
38
  return /* wgsl */ `\
39
- @group(0) @binding(0) var sourceTexture: texture_2d<f32>;
40
- @group(0) @binding(2) var sourceTextureSampler: sampler;
39
+ @group(0) @binding(auto) var sourceTexture: texture_2d<f32>;
40
+ @group(0) @binding(auto) var sourceTextureSampler: sampler;
41
41
 
42
42
  @fragment
43
43
  fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
@@ -54,8 +54,8 @@ fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
54
54
  /** Get a sampling WGSL fragment shader */
55
55
  function getSamplerShaderWGSL(func: string) {
56
56
  return /* wgsl */ `\
57
- @group(0) @binding(0) var sourceTexture: texture_2d<f32>;
58
- @group(0) @binding(2) var sourceTextureSampler: sampler;
57
+ @group(0) @binding(auto) var sourceTexture: texture_2d<f32>;
58
+ @group(0) @binding(auto) var sourceTextureSampler: sampler;
59
59
 
60
60
  @fragment
61
61
  fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4f {
@@ -84,13 +84,11 @@ export class ShaderInputs<
84
84
 
85
85
  // Initialize the modules
86
86
  for (const [name, module] of Object.entries(modules)) {
87
- if (!module) {
88
- continue;
89
- }
90
-
91
- this._addModule(module);
92
- if (module.name && name !== module.name && !this.options.disableWarnings) {
93
- log.warn(`Module name: ${name} vs ${module.name}`)();
87
+ if (module) {
88
+ this._addModule(module);
89
+ if (module.name && name !== module.name && !this.options.disableWarnings) {
90
+ log.warn(`Module name: ${name} vs ${module.name}`)();
91
+ }
94
92
  }
95
93
  }
96
94
  }
@@ -111,26 +109,25 @@ export class ShaderInputs<
111
109
  if (!this.options.disableWarnings) {
112
110
  log.warn(`Module ${name} not found`)();
113
111
  }
114
- continue; // eslint-disable-line no-continue
112
+ } else {
113
+ const oldUniforms = this.moduleUniforms[moduleName];
114
+ const oldBindings = this.moduleBindings[moduleName];
115
+ const uniformsAndBindings =
116
+ module.getUniforms?.(moduleProps, oldUniforms) || (moduleProps as any);
117
+
118
+ const {uniforms, bindings} = splitUniformsAndBindings(
119
+ uniformsAndBindings,
120
+ module.uniformTypes as Readonly<Record<string, CompositeShaderType>>
121
+ );
122
+ this.moduleUniforms[moduleName] = mergeModuleUniforms(
123
+ oldUniforms as Record<string, ShaderModuleUniformValue>,
124
+ uniforms,
125
+ module.uniformTypes as Readonly<Record<string, CompositeShaderType>>
126
+ );
127
+ this.moduleBindings[moduleName] = {...oldBindings, ...bindings};
128
+ // this.moduleUniformsChanged ||= moduleName;
115
129
  }
116
130
 
117
- const oldUniforms = this.moduleUniforms[moduleName];
118
- const oldBindings = this.moduleBindings[moduleName];
119
- const uniformsAndBindings =
120
- module.getUniforms?.(moduleProps, oldUniforms) || (moduleProps as any);
121
-
122
- const {uniforms, bindings} = splitUniformsAndBindings(
123
- uniformsAndBindings,
124
- module.uniformTypes as Readonly<Record<string, CompositeShaderType>>
125
- );
126
- this.moduleUniforms[moduleName] = mergeModuleUniforms(
127
- oldUniforms as Record<string, ShaderModuleUniformValue>,
128
- uniforms,
129
- module.uniformTypes as Readonly<Record<string, CompositeShaderType>>
130
- );
131
- this.moduleBindings[moduleName] = {...oldBindings, ...bindings};
132
- // this.moduleUniformsChanged ||= moduleName;
133
-
134
131
  // console.log(`setProps(${String(moduleName)}`, moduleName, this.moduleUniforms[moduleName])
135
132
  }
136
133
  }
@@ -194,11 +191,9 @@ function mergeModuleUniforms(
194
191
  ): Record<string, ShaderModuleUniformValue> {
195
192
  const mergedUniforms = {...currentUniforms};
196
193
  for (const [key, value] of Object.entries(nextUniforms)) {
197
- if (value === undefined) {
198
- continue;
194
+ if (value !== undefined) {
195
+ mergedUniforms[key] = mergeModuleUniformValue(currentUniforms[key], value, uniformTypes[key]);
199
196
  }
200
-
201
- mergedUniforms[key] = mergeModuleUniformValue(currentUniforms[key], value, uniformTypes[key]);
202
197
  }
203
198
  return mergedUniforms;
204
199
  }
@@ -224,15 +219,13 @@ function mergeModuleUniformValue(
224
219
  const mergedArray = currentArray.slice();
225
220
  for (let index = 0; index < nextValue.length; index++) {
226
221
  const elementValue = nextValue[index];
227
- if (elementValue === undefined) {
228
- continue;
222
+ if (elementValue !== undefined) {
223
+ mergedArray[index] = mergeModuleUniformValue(
224
+ currentArray[index],
225
+ elementValue,
226
+ uniformType[0] as CompositeShaderType
227
+ );
229
228
  }
230
-
231
- mergedArray[index] = mergeModuleUniformValue(
232
- currentArray[index],
233
- elementValue,
234
- uniformType[0] as CompositeShaderType
235
- );
236
229
  }
237
230
  return mergedArray;
238
231
  }
@@ -245,11 +238,9 @@ function mergeModuleUniformValue(
245
238
  const currentObject = isPlainUniformObject(currentValue) ? currentValue : {};
246
239
  const mergedObject: Record<string, ShaderModuleUniformValue | undefined> = {...currentObject};
247
240
  for (const [key, value] of Object.entries(nextValue)) {
248
- if (value === undefined) {
249
- continue;
241
+ if (value !== undefined) {
242
+ mergedObject[key] = mergeModuleUniformValue(currentObject[key], value, uniformStruct[key]);
250
243
  }
251
-
252
- mergedObject[key] = mergeModuleUniformValue(currentObject[key], value, uniformStruct[key]);
253
244
  }
254
245
  return mergedObject as ShaderModuleUniformValue;
255
246
  }