@luma.gl/engine 9.0.0-beta.1 → 9.0.0-beta.10

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 (154) hide show
  1. package/dist/animation/key-frames.js +54 -54
  2. package/dist/animation/timeline.d.ts.map +1 -1
  3. package/dist/animation/timeline.js +95 -100
  4. package/dist/animation-loop/animation-loop-template.d.ts +1 -1
  5. package/dist/animation-loop/animation-loop-template.d.ts.map +1 -1
  6. package/dist/animation-loop/animation-loop-template.js +19 -5
  7. package/dist/animation-loop/animation-loop.d.ts +2 -2
  8. package/dist/animation-loop/animation-loop.d.ts.map +1 -1
  9. package/dist/animation-loop/animation-loop.js +433 -356
  10. package/dist/animation-loop/animation-props.d.ts +2 -2
  11. package/dist/animation-loop/animation-props.d.ts.map +1 -1
  12. package/dist/animation-loop/animation-props.js +0 -1
  13. package/dist/animation-loop/make-animation-loop.d.ts +2 -2
  14. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
  15. package/dist/animation-loop/make-animation-loop.js +28 -24
  16. package/dist/computation.d.ts +95 -0
  17. package/dist/computation.d.ts.map +1 -0
  18. package/dist/computation.js +248 -0
  19. package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
  20. package/dist/debug/copy-texture-to-image.js +39 -42
  21. package/dist/debug/debug-framebuffer.d.ts.map +1 -1
  22. package/dist/debug/debug-framebuffer.js +43 -40
  23. package/dist/debug/debug-shader-layout.js +24 -25
  24. package/dist/debug/pixel-data-utils.d.ts.map +1 -1
  25. package/dist/debug/pixel-data-utils.js +34 -36
  26. package/dist/dist.dev.js +2538 -3027
  27. package/dist/dist.min.js +102 -0
  28. package/dist/geometries/cone-geometry.d.ts +1 -1
  29. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  30. package/dist/geometries/cone-geometry.js +11 -17
  31. package/dist/geometries/cube-geometry.d.ts +1 -1
  32. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  33. package/dist/geometries/cube-geometry.js +190 -61
  34. package/dist/geometries/cylinder-geometry.d.ts +1 -1
  35. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  36. package/dist/geometries/cylinder-geometry.js +9 -14
  37. package/dist/geometries/ico-sphere-geometry.d.ts +1 -1
  38. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  39. package/dist/geometries/ico-sphere-geometry.js +141 -160
  40. package/dist/geometries/plane-geometry.d.ts +1 -1
  41. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  42. package/dist/geometries/plane-geometry.js +92 -110
  43. package/dist/geometries/sphere-geometry.d.ts +1 -1
  44. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  45. package/dist/geometries/sphere-geometry.js +76 -95
  46. package/dist/geometries/truncated-cone-geometry.d.ts +1 -1
  47. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  48. package/dist/geometries/truncated-cone-geometry.js +99 -117
  49. package/dist/geometry/geometry-table.d.ts.map +1 -1
  50. package/dist/geometry/geometry-table.js +3 -1
  51. package/dist/geometry/geometry-utils.js +35 -32
  52. package/dist/geometry/geometry.d.ts.map +1 -1
  53. package/dist/geometry/geometry.js +80 -71
  54. package/dist/geometry/gpu-geometry.d.ts +1 -1
  55. package/dist/geometry/gpu-geometry.d.ts.map +1 -1
  56. package/dist/geometry/gpu-geometry.js +79 -99
  57. package/dist/geometry/gpu-table.js +41 -1
  58. package/dist/index.cjs +725 -409
  59. package/dist/index.cjs.map +7 -0
  60. package/dist/index.d.ts +43 -40
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +6 -1
  63. package/dist/lib/clip-space.d.ts +2 -2
  64. package/dist/lib/clip-space.d.ts.map +1 -1
  65. package/dist/lib/clip-space.js +28 -34
  66. package/dist/lib/pipeline-factory.d.ts +13 -14
  67. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  68. package/dist/lib/pipeline-factory.js +86 -85
  69. package/dist/lib/shader-factory.d.ts +17 -0
  70. package/dist/lib/shader-factory.d.ts.map +1 -0
  71. package/dist/lib/shader-factory.js +46 -0
  72. package/dist/model/model.d.ts +59 -46
  73. package/dist/model/model.d.ts.map +1 -1
  74. package/dist/model/model.js +635 -411
  75. package/dist/scenegraph/group-node.d.ts +1 -1
  76. package/dist/scenegraph/group-node.d.ts.map +1 -1
  77. package/dist/scenegraph/group-node.js +73 -83
  78. package/dist/scenegraph/model-node.d.ts +3 -3
  79. package/dist/scenegraph/model-node.d.ts.map +1 -1
  80. package/dist/scenegraph/model-node.js +31 -24
  81. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
  82. package/dist/scenegraph/scenegraph-node.js +136 -124
  83. package/dist/shader-inputs.d.ts.map +1 -1
  84. package/dist/shader-inputs.js +99 -58
  85. package/dist/transform/buffer-transform.d.ts +1 -1
  86. package/dist/transform/buffer-transform.d.ts.map +1 -1
  87. package/dist/transform/buffer-transform.js +65 -57
  88. package/dist/transform/texture-transform.d.ts +1 -1
  89. package/dist/transform/texture-transform.d.ts.map +1 -1
  90. package/dist/transform/texture-transform.js +109 -114
  91. package/dist.min.js +3 -271
  92. package/package.json +10 -9
  93. package/src/animation/timeline.ts +20 -20
  94. package/src/animation-loop/animation-loop-template.ts +10 -8
  95. package/src/animation-loop/animation-loop.ts +20 -10
  96. package/src/animation-loop/animation-props.ts +1 -1
  97. package/src/animation-loop/make-animation-loop.ts +17 -8
  98. package/src/computation.ts +346 -0
  99. package/src/debug/copy-texture-to-image.ts +9 -11
  100. package/src/debug/debug-framebuffer.ts +16 -3
  101. package/src/debug/debug-shader-layout.ts +1 -1
  102. package/src/debug/pixel-data-utils.ts +3 -6
  103. package/src/geometries/cube-geometry.ts +17 -13
  104. package/src/geometries/ico-sphere-geometry.ts +1 -1
  105. package/src/geometries/plane-geometry.ts +1 -1
  106. package/src/geometries/sphere-geometry.ts +1 -1
  107. package/src/geometries/truncated-cone-geometry.ts +2 -1
  108. package/src/geometry/geometry-table.ts +9 -6
  109. package/src/geometry/geometry-utils.ts +16 -0
  110. package/src/geometry/geometry.ts +9 -6
  111. package/src/geometry/gpu-geometry.ts +18 -11
  112. package/src/index.ts +4 -1
  113. package/src/lib/clip-space.ts +16 -19
  114. package/src/lib/pipeline-factory.ts +71 -64
  115. package/src/lib/shader-factory.ts +57 -0
  116. package/src/model/model.ts +255 -146
  117. package/src/scenegraph/group-node.ts +14 -10
  118. package/src/scenegraph/model-node.ts +2 -2
  119. package/src/scenegraph/scenegraph-node.ts +2 -2
  120. package/src/shader-inputs.ts +19 -12
  121. package/src/transform/buffer-transform.ts +16 -8
  122. package/src/transform/texture-transform.ts +14 -15
  123. package/dist/animation/key-frames.js.map +0 -1
  124. package/dist/animation/timeline.js.map +0 -1
  125. package/dist/animation-loop/animation-loop-template.js.map +0 -1
  126. package/dist/animation-loop/animation-loop.js.map +0 -1
  127. package/dist/animation-loop/animation-props.js.map +0 -1
  128. package/dist/animation-loop/make-animation-loop.js.map +0 -1
  129. package/dist/debug/copy-texture-to-image.js.map +0 -1
  130. package/dist/debug/debug-framebuffer.js.map +0 -1
  131. package/dist/debug/debug-shader-layout.js.map +0 -1
  132. package/dist/debug/pixel-data-utils.js.map +0 -1
  133. package/dist/geometries/cone-geometry.js.map +0 -1
  134. package/dist/geometries/cube-geometry.js.map +0 -1
  135. package/dist/geometries/cylinder-geometry.js.map +0 -1
  136. package/dist/geometries/ico-sphere-geometry.js.map +0 -1
  137. package/dist/geometries/plane-geometry.js.map +0 -1
  138. package/dist/geometries/sphere-geometry.js.map +0 -1
  139. package/dist/geometries/truncated-cone-geometry.js.map +0 -1
  140. package/dist/geometry/geometry-table.js.map +0 -1
  141. package/dist/geometry/geometry-utils.js.map +0 -1
  142. package/dist/geometry/geometry.js.map +0 -1
  143. package/dist/geometry/gpu-geometry.js.map +0 -1
  144. package/dist/geometry/gpu-table.js.map +0 -1
  145. package/dist/index.js.map +0 -1
  146. package/dist/lib/clip-space.js.map +0 -1
  147. package/dist/lib/pipeline-factory.js.map +0 -1
  148. package/dist/model/model.js.map +0 -1
  149. package/dist/scenegraph/group-node.js.map +0 -1
  150. package/dist/scenegraph/model-node.js.map +0 -1
  151. package/dist/scenegraph/scenegraph-node.js.map +0 -1
  152. package/dist/shader-inputs.js.map +0 -1
  153. package/dist/transform/buffer-transform.js.map +0 -1
  154. package/dist/transform/texture-transform.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@luma.gl/engine",
3
- "version": "9.0.0-beta.1",
4
- "description": "WebGL2 Components for High Performance Rendering and Computation",
3
+ "version": "9.0.0-beta.10",
4
+ "description": "3D Engine Components for luma.gl",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "publishConfig": {
@@ -35,17 +35,18 @@
35
35
  ],
36
36
  "sideEffects": false,
37
37
  "scripts": {
38
- "build-bundle": "ocular-bundle ./src/index.ts",
39
- "pre-build": "npm run build-bundle && npm run build-bundle -- --env=dev"
38
+ "build-minified-bundle": "ocular-bundle ./bundle.ts --output=dist/dist.min.js",
39
+ "build-dev-bundle": "ocular-bundle ./bundle.ts --output=dist/dist.dev.js --env=dev",
40
+ "prepublishOnly": "npm run build-minified-bundle && npm run build-dev-bundle"
41
+ },
42
+ "peerDependencies": {
43
+ "@luma.gl/core": "^9.0.0-beta"
40
44
  },
41
45
  "dependencies": {
42
- "@babel/runtime": "^7.0.0",
43
- "@luma.gl/constants": "9.0.0-beta.1",
44
- "@luma.gl/core": "9.0.0-beta.1",
45
- "@luma.gl/shadertools": "9.0.0-beta.1",
46
+ "@luma.gl/shadertools": "9.0.0-beta.10",
46
47
  "@math.gl/core": "^4.0.0",
47
48
  "@probe.gl/log": "^4.0.2",
48
49
  "@probe.gl/stats": "^4.0.2"
49
50
  },
50
- "gitHead": "5fb42f651e80825336a372ca5a66de7d55611ddf"
51
+ "gitHead": "1b36500a878e1b365425826750320dde7d6929bb"
51
52
  }
@@ -1,4 +1,5 @@
1
- // luma.gl, MIT license
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
2
3
  // Copyright (c) vis.gl contributors
3
4
 
4
5
  /**
@@ -9,30 +10,30 @@
9
10
  * @param repeat = 1
10
11
  */
11
12
  export type ChannelOptions = {
12
- delay?: number
13
- duration?: number
14
- rate?: number
15
- repeat?: number
16
- }
13
+ delay?: number;
14
+ duration?: number;
15
+ rate?: number;
16
+ repeat?: number;
17
+ };
17
18
 
18
19
  export type AnimationOptions = {
19
- setTime: (time: number) => void
20
- }
20
+ setTime: (time: number) => void;
21
+ };
21
22
 
22
- type Channel = {
23
- time: number
24
- delay: number
25
- duration: number
26
- rate: number
27
- repeat: number
28
- }
23
+ type Channel = {
24
+ time: number;
25
+ delay: number;
26
+ duration: number;
27
+ rate: number;
28
+ repeat: number;
29
+ };
29
30
 
30
31
  type Animation = {
31
32
  channel?: number;
32
33
  animation: {
33
- setTime: (time: number) => void
34
- }
35
- }
34
+ setTime: (time: number) => void;
35
+ };
36
+ };
36
37
 
37
38
  let channelHandles = 1;
38
39
  let animationHandles = 1;
@@ -44,8 +45,7 @@ export class Timeline {
44
45
  playing: boolean = false;
45
46
  lastEngineTime: number = -1;
46
47
 
47
- constructor() {
48
- }
48
+ constructor() {}
49
49
 
50
50
  addChannel(props: ChannelOptions): number {
51
51
  const {delay = 0, duration = Number.POSITIVE_INFINITY, rate = 1, repeat = 1} = props;
@@ -3,21 +3,23 @@ import type {AnimationProps} from './animation-props';
3
3
  /**
4
4
  * Minimal class that represents a "componentized" rendering life cycle
5
5
  * (resource construction, repeated rendering, resource destruction)
6
- *
7
- * @note A motivation for this class compared to the raw animation loop is
8
- * that it simplifies TypeScript code by allowing resources to be typed unconditionally
6
+ *
7
+ * @note A motivation for this class compared to the raw animation loop is
8
+ * that it simplifies TypeScript code by allowing resources to be typed unconditionally
9
9
  * since they are allocated in the constructor rather than in onInitialized
10
- *
10
+ *
11
11
  * @note Introduced in luma.gl v9
12
- *
13
- * @example AnimationLoopTemplate is intended to be subclassed,
12
+ *
13
+ * @example AnimationLoopTemplate is intended to be subclassed,
14
14
  * but the subclass should not be instantiated directly. Instead the subclass
15
- * (i.e. the constructor of the subclass) should be used
15
+ * (i.e. the constructor of the subclass) should be used
16
16
  * as an argument to create an AnimationLoop.
17
17
  */
18
18
  export abstract class AnimationLoopTemplate {
19
19
  constructor(animationProps?: AnimationProps) {}
20
- async onInitialize(animationProps: AnimationProps): Promise<unknown> { return null; }
20
+ async onInitialize(animationProps: AnimationProps): Promise<unknown> {
21
+ return null;
22
+ }
21
23
  abstract onRender(animationProps: AnimationProps): unknown;
22
24
  abstract onFinalize(animationProps: AnimationProps): void;
23
25
  }
@@ -1,4 +1,5 @@
1
- // luma.gl, MIT license
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
2
3
  // Copyright (c) vis.gl contributors
3
4
 
4
5
  import {luma, Device} from '@luma.gl/core';
@@ -32,23 +33,25 @@ export type MutableAnimationLoopProps = {
32
33
  autoResizeViewport?: boolean;
33
34
  autoResizeDrawingBuffer?: boolean;
34
35
  useDevicePixels?: number | boolean;
35
- }
36
+ };
36
37
 
37
38
  const DEFAULT_ANIMATION_LOOP_PROPS: Required<AnimationLoopProps> = {
38
39
  device: null!,
39
40
 
40
41
  onAddHTML: () => '',
41
- onInitialize: async () => { return null; },
42
+ onInitialize: async () => {
43
+ return null;
44
+ },
42
45
  onRender: () => {},
43
46
  onFinalize: () => {},
44
- onError: (error) => console.error(error), // eslint-disable-line no-console
47
+ onError: error => console.error(error), // eslint-disable-line no-console
45
48
 
46
49
  stats: luma.stats.get(`animation-loop-${statIdCounter++}`),
47
50
 
48
51
  // view parameters
49
52
  useDevicePixels: true,
50
53
  autoResizeViewport: false,
51
- autoResizeDrawingBuffer: false,
54
+ autoResizeDrawingBuffer: false
52
55
  };
53
56
 
54
57
  /** Convenient animation loop */
@@ -148,7 +151,6 @@ export class AnimationLoop {
148
151
  this._running = true;
149
152
 
150
153
  try {
151
-
152
154
  let appContext;
153
155
  if (!this._initialized) {
154
156
  this._initialized = true;
@@ -174,7 +176,7 @@ export class AnimationLoop {
174
176
 
175
177
  return this;
176
178
  } catch (err: unknown) {
177
- const error = err instanceof Error ? err : new Error('Unknown error')
179
+ const error = err instanceof Error ? err : new Error('Unknown error');
178
180
  this.props.onError(error);
179
181
  // this._running = false; // TODO
180
182
  throw error;
@@ -242,7 +244,7 @@ export class AnimationLoop {
242
244
  this.setNeedsRedraw('waitForRender');
243
245
 
244
246
  if (!this._nextFramePromise) {
245
- this._nextFramePromise = new Promise((resolve) => {
247
+ this._nextFramePromise = new Promise(resolve => {
246
248
  this._resolveNextFrame = resolve;
247
249
  });
248
250
  }
@@ -461,7 +463,7 @@ export class AnimationLoop {
461
463
  }
462
464
  }
463
465
 
464
- _getSizeAndAspect(): {width: number; height: number; aspect: number} {
466
+ _getSizeAndAspect(): {width: number; height: number; aspect: number} {
465
467
  if (!this.device) {
466
468
  return {width: 1, height: 1, aspect: 1};
467
469
  }
@@ -485,10 +487,18 @@ export class AnimationLoop {
485
487
 
486
488
  /** Default viewport setup */
487
489
  _resizeViewport(): void {
490
+ // TODO can we use canvas context to code this in a portable way?
488
491
  // @ts-expect-error Expose on canvasContext
489
492
  if (this.props.autoResizeViewport && this.device.gl) {
490
493
  // @ts-expect-error Expose canvasContext
491
- this.device.gl.viewport(0, 0, this.device.gl.drawingBufferWidth, this.device.gl.drawingBufferHeight);
494
+ this.device.gl.viewport(
495
+ 0,
496
+ 0,
497
+ // @ts-expect-error Expose canvasContext
498
+ this.device.gl.drawingBufferWidth,
499
+ // @ts-expect-error Expose canvasContext
500
+ this.device.gl.drawingBufferHeight
501
+ );
492
502
  }
493
503
  }
494
504
 
@@ -1,5 +1,5 @@
1
1
  import {Device} from '@luma.gl/core';
2
- import {Timeline} from '../animation/timeline'
2
+ import {Timeline} from '../animation/timeline';
3
3
  import type {AnimationLoop} from './animation-loop';
4
4
 
5
5
  /** Properties passed to every render frame */
@@ -1,20 +1,29 @@
1
- // luma.gl, MIT license
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
2
5
  import {luma} from '@luma.gl/core';
3
- import {AnimationLoopTemplate} from './animation-loop-template'
4
- import {AnimationLoop, AnimationLoopProps} from './animation-loop'
6
+ import {AnimationLoopTemplate} from './animation-loop-template';
7
+ import {AnimationLoop, AnimationLoopProps} from './animation-loop';
5
8
  import type {AnimationProps} from './animation-props';
6
9
 
7
- export type MakeAnimationLoopProps = Omit<AnimationLoopProps, 'onCreateDevice' | 'onInitialize' | 'onRedraw' | 'onFinalize'>;
10
+ export type MakeAnimationLoopProps = Omit<
11
+ AnimationLoopProps,
12
+ 'onCreateDevice' | 'onInitialize' | 'onRedraw' | 'onFinalize'
13
+ >;
8
14
 
9
15
  /** Instantiates and runs the render loop */
10
- export function makeAnimationLoop(AnimationLoopTemplateCtor: typeof AnimationLoopTemplate, props?: MakeAnimationLoopProps): AnimationLoop {
16
+ export function makeAnimationLoop(
17
+ AnimationLoopTemplateCtor: typeof AnimationLoopTemplate,
18
+ props?: MakeAnimationLoopProps
19
+ ): AnimationLoop {
11
20
  let renderLoop: AnimationLoopTemplate | null = null;
12
21
 
13
22
  const device = props?.device || luma.createDevice();
14
23
 
15
24
  // Create an animation loop;
16
25
  const animationLoop = new AnimationLoop({
17
- ... props,
26
+ ...props,
18
27
 
19
28
  device,
20
29
 
@@ -26,7 +35,7 @@ export function makeAnimationLoop(AnimationLoopTemplateCtor: typeof AnimationLoo
26
35
  },
27
36
 
28
37
  onRender: (animationProps: AnimationProps) => renderLoop?.onRender(animationProps),
29
-
38
+
30
39
  onFinalize: (animationProps: AnimationProps) => renderLoop?.onFinalize(animationProps)
31
40
  });
32
41
 
@@ -35,7 +44,7 @@ export function makeAnimationLoop(AnimationLoopTemplateCtor: typeof AnimationLoo
35
44
  // @ts-ignore
36
45
  // eslint-disable-next-line no-invalid-this
37
46
  return this.AnimationLoopTemplateCtor.info;
38
- }
47
+ };
39
48
 
40
49
  // Start the loop automatically
41
50
  // animationLoop.start();
@@ -0,0 +1,346 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {TypedArray} from '@luma.gl/core';
6
+ import type {DeviceFeature, ComputePipelineProps, Shader, Binding} from '@luma.gl/core';
7
+ import {Device, Buffer, ComputePipeline, ComputePass, UniformStore} from '@luma.gl/core';
8
+ import {log, uid, isNumberArray} from '@luma.gl/core';
9
+ import {getTypedArrayFromDataType} from '@luma.gl/core';
10
+ import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
11
+ import {ShaderAssembler, getShaderLayoutFromWGSL} from '@luma.gl/shadertools';
12
+ import {ShaderInputs} from './shader-inputs';
13
+ import {PipelineFactory} from './lib/pipeline-factory';
14
+ import {ShaderFactory} from './lib/shader-factory';
15
+ // import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
16
+
17
+ const LOG_DRAW_PRIORITY = 2;
18
+ const LOG_DRAW_TIMEOUT = 10000;
19
+
20
+ export type ComputationProps = Omit<ComputePipelineProps, 'shader'> & {
21
+ source?: string;
22
+
23
+ /** shadertool shader modules (added to shader code) */
24
+ modules?: ShaderModule[];
25
+ /** Shadertool module defines (configures shader code)*/
26
+ defines?: Record<string, string | number | boolean>;
27
+ // TODO - injections, hooks etc?
28
+
29
+ /** Shader inputs, used to generated uniform buffers and bindings */
30
+ shaderInputs?: ShaderInputs;
31
+
32
+ /** Bindings */
33
+ bindings?: Record<string, Binding>;
34
+
35
+ /** Show shader source in browser? */
36
+ debugShaders?: 'never' | 'errors' | 'warnings' | 'always';
37
+
38
+ /** Factory used to create a {@link ComputePipeline}. Defaults to {@link Device} default factory. */
39
+ pipelineFactory?: PipelineFactory;
40
+ /** Factory used to create a {@link Shader}. Defaults to {@link Device} default factory. */
41
+ shaderFactory?: ShaderFactory;
42
+ /** Shader assembler. Defaults to the ShaderAssembler.getShaderAssembler() */
43
+ shaderAssembler?: ShaderAssembler;
44
+ };
45
+
46
+ /**
47
+ * v9 Model API
48
+ * A model
49
+ * - automatically reuses pipelines (programs) when possible
50
+ * - automatically rebuilds pipelines if necessary to accommodate changed settings
51
+ * shadertools integration
52
+ * - accepts modules and performs shader transpilation
53
+ */
54
+ export class Computation {
55
+ static defaultProps: Required<ComputationProps> = {
56
+ ...ComputePipeline.defaultProps,
57
+ id: 'unnamed',
58
+ handle: undefined,
59
+ userData: {},
60
+
61
+ source: '',
62
+ modules: [],
63
+ defines: {},
64
+
65
+ bindings: undefined!,
66
+ shaderInputs: undefined!,
67
+
68
+ pipelineFactory: undefined!,
69
+ shaderFactory: undefined!,
70
+ shaderAssembler: ShaderAssembler.getDefaultShaderAssembler(),
71
+
72
+ debugShaders: undefined
73
+ };
74
+
75
+ readonly device: Device;
76
+ readonly id: string;
77
+
78
+ readonly pipelineFactory: PipelineFactory;
79
+ readonly shaderFactory: ShaderFactory;
80
+
81
+ userData: {[key: string]: any} = {};
82
+
83
+ /** Bindings (textures, samplers, uniform buffers) */
84
+ bindings: Record<string, Binding> = {};
85
+
86
+ /** The underlying GPU "program". @note May be recreated if parameters change */
87
+ pipeline: ComputePipeline;
88
+ /** the underlying compiled compute shader */
89
+ shader: Shader;
90
+ source: string;
91
+
92
+ /** ShaderInputs instance */
93
+ shaderInputs: ShaderInputs;
94
+
95
+ _uniformStore: UniformStore;
96
+
97
+ _pipelineNeedsUpdate: string | false = 'newly created';
98
+
99
+ private _getModuleUniforms: (props?: Record<string, Record<string, any>>) => Record<string, any>;
100
+ private props: Required<ComputationProps>;
101
+
102
+ private _destroyed = false;
103
+
104
+ constructor(device: Device, props: ComputationProps) {
105
+ if (device.type !== 'webgpu') {
106
+ throw new Error('Computation is only supported in WebGPU');
107
+ }
108
+
109
+ this.props = {...Computation.defaultProps, ...props};
110
+ props = this.props;
111
+ this.id = props.id || uid('model');
112
+ this.device = device;
113
+
114
+ Object.assign(this.userData, props.userData);
115
+
116
+ // Setup shader module inputs
117
+ const moduleMap = Object.fromEntries(
118
+ this.props.modules?.map(module => [module.name, module]) || []
119
+ );
120
+ this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
121
+
122
+ // Support WGSL shader layout introspection
123
+ // TODO - Don't modify props!!
124
+ this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source);
125
+
126
+ // Setup shader assembler
127
+ const platformInfo = getPlatformInfo(device);
128
+
129
+ // Extract modules from shader inputs if not supplied
130
+ const modules =
131
+ (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
132
+
133
+ this.pipelineFactory =
134
+ props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
135
+ this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
136
+
137
+ const {source, getUniforms} = this.props.shaderAssembler.assembleShader({
138
+ platformInfo,
139
+ ...this.props,
140
+ modules
141
+ });
142
+
143
+ this.source = source;
144
+
145
+ this._getModuleUniforms = getUniforms;
146
+
147
+ // Create the pipeline
148
+ // @note order is important
149
+ this.pipeline = this._updatePipeline();
150
+
151
+ // Apply any dynamic settings that will not trigger pipeline change
152
+ if (props.bindings) {
153
+ this.setBindings(props.bindings);
154
+ }
155
+
156
+ // Catch any access to non-standard props
157
+ Object.seal(this);
158
+ }
159
+
160
+ destroy(): void {
161
+ if (this._destroyed) return;
162
+ this.pipelineFactory.release(this.pipeline);
163
+ this.shaderFactory.release(this.shader);
164
+ this._uniformStore.destroy();
165
+ this._destroyed = true;
166
+ }
167
+
168
+ // Draw call
169
+
170
+ predraw() {
171
+ // Update uniform buffers if needed
172
+ this.updateShaderInputs();
173
+ }
174
+
175
+ dispatch(computePass: ComputePass, x: number, y?: number, z?: number): void {
176
+ try {
177
+ this._logDrawCallStart();
178
+
179
+ // Check if the pipeline is invalidated
180
+ // TODO - this is likely the worst place to do this from performance perspective. Perhaps add a predraw()?
181
+ this.pipeline = this._updatePipeline();
182
+
183
+ // Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
184
+ // Any caching needs to be done inside the pipeline functions
185
+ this.pipeline.setBindings(this.bindings);
186
+ computePass.setPipeline(this.pipeline);
187
+ // @ts-expect-error
188
+ computePass.setBindings([]);
189
+
190
+ computePass.dispatch(x, y, z);
191
+ } finally {
192
+ this._logDrawCallEnd();
193
+ }
194
+ }
195
+
196
+ // Update fixed fields (can trigger pipeline rebuild)
197
+
198
+ // Update dynamic fields
199
+
200
+ /**
201
+ * Updates the vertex count (used in draw calls)
202
+ * @note Any attributes with stepMode=vertex need to be at least this big
203
+ */
204
+ setVertexCount(vertexCount: number): void {
205
+ // this.vertexCount = vertexCount;
206
+ }
207
+
208
+ /**
209
+ * Updates the instance count (used in draw calls)
210
+ * @note Any attributes with stepMode=instance need to be at least this big
211
+ */
212
+ setInstanceCount(instanceCount: number): void {
213
+ // this.instanceCount = instanceCount;
214
+ }
215
+
216
+ setShaderInputs(shaderInputs: ShaderInputs): void {
217
+ this.shaderInputs = shaderInputs;
218
+ this._uniformStore = new UniformStore(this.shaderInputs.modules);
219
+ // Create uniform buffer bindings for all modules
220
+ for (const moduleName of Object.keys(this.shaderInputs.modules)) {
221
+ const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
222
+ this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Updates shader module settings (which results in uniforms being set)
228
+ */
229
+ setShaderModuleProps(props: Record<string, any>): void {
230
+ const uniforms = this._getModuleUniforms(props);
231
+
232
+ // Extract textures & framebuffers set by the modules
233
+ // TODO better way to extract bindings
234
+ const keys = Object.keys(uniforms).filter(k => {
235
+ const uniform = uniforms[k];
236
+ return !isNumberArray(uniform) && typeof uniform !== 'number' && typeof uniform !== 'boolean';
237
+ });
238
+ const bindings: Record<string, Binding> = {};
239
+ for (const k of keys) {
240
+ bindings[k] = uniforms[k];
241
+ delete uniforms[k];
242
+ }
243
+ }
244
+
245
+ updateShaderInputs(): void {
246
+ this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
247
+ }
248
+
249
+ /**
250
+ * Sets bindings (textures, samplers, uniform buffers)
251
+ */
252
+ setBindings(bindings: Record<string, Binding>): void {
253
+ Object.assign(this.bindings, bindings);
254
+ }
255
+
256
+ _setPipelineNeedsUpdate(reason: string): void {
257
+ this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
258
+ }
259
+
260
+ _updatePipeline(): ComputePipeline {
261
+ if (this._pipelineNeedsUpdate) {
262
+ let prevShader: Shader | null = null;
263
+ if (this.pipeline) {
264
+ log.log(
265
+ 1,
266
+ `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`
267
+ )();
268
+ prevShader = this.shader;
269
+ }
270
+
271
+ this._pipelineNeedsUpdate = false;
272
+
273
+ this.shader = this.shaderFactory.createShader({
274
+ id: `${this.id}-fragment`,
275
+ stage: 'compute',
276
+ source: this.source,
277
+ debug: this.props.debugShaders
278
+ });
279
+
280
+ this.pipeline = this.pipelineFactory.createComputePipeline({
281
+ ...this.props,
282
+ shader: this.shader
283
+ });
284
+
285
+ if (prevShader) {
286
+ this.shaderFactory.release(prevShader);
287
+ }
288
+ }
289
+ return this.pipeline;
290
+ }
291
+
292
+ /** Throttle draw call logging */
293
+ _lastLogTime = 0;
294
+ _logOpen = false;
295
+
296
+ _logDrawCallStart(): void {
297
+ // IF level is 4 or higher, log every frame.
298
+ const logDrawTimeout = log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
299
+ if (log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
300
+ return;
301
+ }
302
+
303
+ this._lastLogTime = Date.now();
304
+ this._logOpen = true;
305
+
306
+ log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, {collapsed: log.level <= 2})();
307
+ }
308
+
309
+ _logDrawCallEnd(): void {
310
+ if (this._logOpen) {
311
+ // const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.props.shaderLayout, this.id);
312
+
313
+ // log.table(logLevel, attributeTable)();
314
+ // log.table(logLevel, uniformTable)();
315
+ // log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
316
+
317
+ const uniformTable = this.shaderInputs.getDebugTable();
318
+ log.table(LOG_DRAW_PRIORITY, uniformTable)();
319
+
320
+ log.groupEnd(LOG_DRAW_PRIORITY)();
321
+ this._logOpen = false;
322
+ }
323
+ }
324
+
325
+ protected _drawCount = 0;
326
+
327
+ // TODO - fix typing of luma data types
328
+ _getBufferOrConstantValues(attribute: Buffer | TypedArray, dataType: any): string {
329
+ const TypedArrayConstructor = getTypedArrayFromDataType(dataType);
330
+ const typedArray =
331
+ attribute instanceof Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
332
+ return typedArray.toString();
333
+ }
334
+ }
335
+
336
+ /** Create a shadertools platform info from the Device */
337
+ export function getPlatformInfo(device: Device): PlatformInfo {
338
+ return {
339
+ type: device.type,
340
+ shaderLanguage: device.info.shadingLanguage,
341
+ shaderLanguageVersion: device.info.shadingLanguageVersion as 100 | 300,
342
+ gpu: device.info.gpu,
343
+ // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
344
+ features: device.features as unknown as Set<DeviceFeature>
345
+ };
346
+ }
@@ -1,6 +1,8 @@
1
- // luma.gl, MIT license
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
2
5
  import {Texture, Framebuffer} from '@luma.gl/core';
3
- import {GL} from '@luma.gl/constants';
4
6
  import {flipRows, scalePixels} from './pixel-data-utils';
5
7
 
6
8
  /**
@@ -8,7 +10,7 @@ import {flipRows, scalePixels} from './pixel-data-utils';
8
10
  * @todo - support gl.readBuffer
9
11
  */
10
12
  export type CopyTextureToImageOptions = {
11
- sourceAttachment?: number;
13
+ sourceAttachment?: number;
12
14
  targetMaxHeight?: number;
13
15
  targetImage?: HTMLImageElement;
14
16
  };
@@ -16,15 +18,14 @@ export type CopyTextureToImageOptions = {
16
18
  /**
17
19
  * Reads pixels from a Framebuffer or Texture object into an HTML Image
18
20
  * @todo - can we move this to @luma.gl/core?
19
- * @param source
21
+ * @param source
20
22
  * @param options options passed to copyToDataUrl
21
- * @returns
23
+ * @returns
22
24
  */
23
25
  export function copyTextureToImage(
24
26
  source: Texture | Framebuffer,
25
27
  options?: CopyTextureToImageOptions
26
28
  ): HTMLImageElement {
27
-
28
29
  const dataUrl = copyTextureToDataUrl(source, options);
29
30
  const targetImage: HTMLImageElement = options?.targetImage || new Image();
30
31
  targetImage.src = dataUrl;
@@ -36,16 +37,13 @@ export function copyTextureToImage(
36
37
  * Reads pixels from a Framebuffer or Texture object to a dataUrl
37
38
  * @todo - can we move this to @luma.gl/core?
38
39
  * @param source texture or framebuffer to read from
39
- * @param options
40
+ * @param options
40
41
  */
41
42
  export function copyTextureToDataUrl(
42
43
  source: Texture | Framebuffer,
43
44
  options: CopyTextureToImageOptions = {}
44
45
  ): string {
45
- const {
46
- sourceAttachment = GL.COLOR_ATTACHMENT0, // TODO - support gl.readBuffer
47
- targetMaxHeight = Number.MAX_SAFE_INTEGER
48
- } = options;
46
+ const {sourceAttachment, targetMaxHeight = Number.MAX_SAFE_INTEGER} = options;
49
47
 
50
48
  let data = source.device.readPixelsToArrayWebGL(source, {sourceAttachment});
51
49