@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
@@ -10,7 +10,21 @@ let ctx: CanvasRenderingContext2D | null = null;
10
10
  // eslint-disable-next-line
11
11
  export function debugFramebuffer(
12
12
  fbo: Framebuffer | Texture,
13
- {id, minimap, opaque, top = '0', left = '0', rgbaScale = 1}: {id: string, minimap?: boolean; opaque?: boolean, top?: string, left?: string, rgbaScale?: number}
13
+ {
14
+ id,
15
+ minimap,
16
+ opaque,
17
+ top = '0',
18
+ left = '0',
19
+ rgbaScale = 1
20
+ }: {
21
+ id: string;
22
+ minimap?: boolean;
23
+ opaque?: boolean;
24
+ top?: string;
25
+ left?: string;
26
+ rgbaScale?: number;
27
+ }
14
28
  ) {
15
29
  if (!canvas) {
16
30
  canvas = document.createElement('canvas');
@@ -34,7 +48,6 @@ export function debugFramebuffer(
34
48
  canvas.height = fbo.height / 2;
35
49
  canvas.style.width = '400px';
36
50
  canvas.style.height = '400px';
37
-
38
51
  }
39
52
 
40
53
  // const image = copyTextureToImage(fbo, {targetMaxHeight: 100, targetImage});
@@ -54,4 +67,4 @@ export function debugFramebuffer(
54
67
  imageData.data[offset + i + 3] = opaque ? 255 : color[i + 3] * rgbaScale;
55
68
  }
56
69
  ctx.putImageData(imageData, 0, 0);
57
- };
70
+ }
@@ -8,7 +8,7 @@ import type {ShaderLayout} from '@luma.gl/core';
8
8
  * Extracts a table suitable for `console.table()` from a shader layout to assist in debugging.
9
9
  * @param layout shader layout
10
10
  * @param name app should provide the most meaningful name, usually the model or pipeline name / id.
11
- * @returns
11
+ * @returns
12
12
  */
13
13
  export function getDebugTableForShaderLayout(
14
14
  layout: ShaderLayout,
@@ -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 {TypedArray} from '@luma.gl/core';
@@ -33,11 +34,7 @@ export function flipRows(options: {
33
34
  }
34
35
  }
35
36
 
36
- export function scalePixels(options: {
37
- data: TypedArray;
38
- width: number;
39
- height: number;
40
- }): {
37
+ export function scalePixels(options: {data: TypedArray; width: number; height: number}): {
41
38
  data: Uint8Array;
42
39
  width: number;
43
40
  height: number;
@@ -11,19 +11,23 @@ export type CubeGeometryProps = {
11
11
  export class CubeGeometry extends Geometry {
12
12
  constructor(props: CubeGeometryProps = {}) {
13
13
  const {id = uid('cube-geometry'), indices = true} = props;
14
- super(indices ? {
15
- ...props,
16
- id,
17
- topology: 'triangle-list',
18
- indices: {size: 1, value: CUBE_INDICES},
19
- attributes: {...ATTRIBUTES, ...props.attributes}
20
- } : {
21
- ...props,
22
- id,
23
- topology: 'triangle-list',
24
- indices: undefined,
25
- attributes: {...NON_INDEXED_ATTRIBUTES, ...props.attributes}
26
- });
14
+ super(
15
+ indices
16
+ ? {
17
+ ...props,
18
+ id,
19
+ topology: 'triangle-list',
20
+ indices: {size: 1, value: CUBE_INDICES},
21
+ attributes: {...ATTRIBUTES, ...props.attributes}
22
+ }
23
+ : {
24
+ ...props,
25
+ id,
26
+ topology: 'triangle-list',
27
+ indices: undefined,
28
+ attributes: {...NON_INDEXED_ATTRIBUTES, ...props.attributes}
29
+ }
30
+ );
27
31
  }
28
32
  }
29
33
 
@@ -11,7 +11,7 @@ export type IcoSphereGeometryProps = {
11
11
  id?: string;
12
12
  radius?: number;
13
13
  iterations?: number;
14
- attributes?: any
14
+ attributes?: any;
15
15
  };
16
16
 
17
17
  export class IcoSphereGeometry extends Geometry {
@@ -5,7 +5,7 @@ import {unpackIndexedGeometry} from '../geometry/geometry-utils';
5
5
  export type PlaneGeometryProps = {
6
6
  id?: string;
7
7
  radius?: number;
8
- attributes?: any
8
+ attributes?: any;
9
9
  };
10
10
 
11
11
  // Primitives inspired by TDL http://code.google.com/p/webglsamples/,
@@ -6,7 +6,7 @@ export type SphereGeometryProps = {
6
6
  radius?: number;
7
7
  nlat?: number;
8
8
  nlong?: number;
9
- attributes?: any
9
+ attributes?: any;
10
10
  };
11
11
 
12
12
  // Primitives inspired by TDL http://code.google.com/p/webglsamples/,
@@ -36,7 +36,8 @@ export class TruncatedConeGeometry extends Geometry {
36
36
  POSITION: {size: 3, value: attributes.POSITION},
37
37
  NORMAL: {size: 3, value: attributes.NORMAL},
38
38
  TEXCOORD_0: {size: 2, value: attributes.TEXCOORD_0},
39
- ...props.attributes}
39
+ ...props.attributes
40
+ }
40
41
  });
41
42
  }
42
43
  }
@@ -1,4 +1,7 @@
1
- // luma.gl, MIT license
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
2
5
  import type {TypedArray, VertexFormat} from '@luma.gl/core';
3
6
 
4
7
  /** Holds one geometry */
@@ -6,11 +9,11 @@ export type GeometryTable = {
6
9
  length: number;
7
10
  schema?: Record<string, VertexFormat>;
8
11
  attributes: {
9
- POSITION: TypedArray,
10
- NORMAL: TypedArray,
11
- TEXCOORD_0: TypedArray,
12
- [key: string]: TypedArray,
12
+ POSITION: TypedArray;
13
+ NORMAL: TypedArray;
14
+ TEXCOORD_0: TypedArray;
15
+ [key: string]: TypedArray;
13
16
  };
14
17
  indices?: Uint16Array | Uint32Array;
15
18
  topology?: 'point-list' | 'line-list' | 'line-strip' | 'triangle-list' | 'triangle-strip';
16
- }
19
+ };
@@ -29,3 +29,19 @@ export function unpackIndexedGeometry(geometry: any) {
29
29
  attributes: Object.assign({}, attributes, unpackedAttributes)
30
30
  };
31
31
  }
32
+
33
+ // export function calculateVertexNormals(positions: Float32Array): Uint8Array {
34
+ // let normals = new Uint8Array(positions.length / 3);
35
+
36
+ // for (let i = 0; i < positions.length; i++) {
37
+ // const vec1 = new Vector3(positions.subarray(i * 3, i + 0, i + 3));
38
+ // const vec2 = new Vector3(positions.subarray(i + 3, i + 6));
39
+ // const vec3 = new Vector3(positions.subarray(i + 6, i + 9));
40
+
41
+ // const normal = new Vector3(vec1).cross(vec2).normalize();
42
+ // normals.set(normal[0], i + 4);
43
+ // normals.set(normal[1], i + 4 + 1);
44
+ // normals.set(normal[2], i + 2);
45
+ // }
46
+ // const normal = new Vector3(vec1).cross(vec2).normalize();
47
+ // }
@@ -1,4 +1,7 @@
1
- // luma.gl, MIT license
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
2
5
  import type {PrimitiveTopology, TypedArray} from '@luma.gl/core';
3
6
  import {uid, assert} from '@luma.gl/core';
4
7
 
@@ -98,7 +101,7 @@ export class Geometry {
98
101
  return this.vertexCount;
99
102
  }
100
103
 
101
- /**
104
+ /**
102
105
  * Return an object with all attributes plus indices added as a field.
103
106
  * TODO Geometry types are a mess
104
107
  */
@@ -118,10 +121,10 @@ export class Geometry {
118
121
  * type: indices, vertices, uvs
119
122
  * size: elements per vertex
120
123
  * target: WebGL buffer type (string or constant)
121
- *
122
- * @param attributes
123
- * @param indices
124
- * @returns
124
+ *
125
+ * @param attributes
126
+ * @param indices
127
+ * @returns
125
128
  */
126
129
  _setAttributes(attributes: Record<string, GeometryAttribute>, indices: any): this {
127
130
  return this;
@@ -48,11 +48,10 @@ export class GPUGeometry {
48
48
  }
49
49
 
50
50
  destroy(): void {
51
- this.indices.destroy();
52
- this.attributes.positions.destroy();
53
- this.attributes.normals.destroy();
54
- this.attributes.texCoords.destroy();
55
- this.attributes.colors?.destroy();
51
+ this.indices?.destroy();
52
+ for (const attribute of Object.values(this.attributes)) {
53
+ attribute.destroy();
54
+ }
56
55
  }
57
56
 
58
57
  getVertexCount(): number {
@@ -101,7 +100,7 @@ export function getIndexBufferFromGeometry(device: Device, geometry: Geometry):
101
100
  export function getAttributeBuffersFromGeometry(
102
101
  device: Device,
103
102
  geometry: Geometry
104
- ): {attributes: Record<string, Buffer>, bufferLayout: BufferLayout[], vertexCount: number} {
103
+ ): {attributes: Record<string, Buffer>; bufferLayout: BufferLayout[]; vertexCount: number} {
105
104
  const bufferLayout: BufferLayout[] = [];
106
105
 
107
106
  const attributes: Record<string, Buffer> = {};
@@ -109,17 +108,25 @@ export function getAttributeBuffersFromGeometry(
109
108
  let name: string = attributeName;
110
109
  // TODO Map some GLTF attribute names (is this still needed?)
111
110
  switch (attributeName) {
112
- case 'POSITION': name = 'positions'; break;
113
- case 'NORMAL': name = 'normals'; break;
114
- case 'TEXCOORD_0': name = 'texCoords'; break;
115
- case 'COLOR_0': name = 'colors'; break;
111
+ case 'POSITION':
112
+ name = 'positions';
113
+ break;
114
+ case 'NORMAL':
115
+ name = 'normals';
116
+ break;
117
+ case 'TEXCOORD_0':
118
+ name = 'texCoords';
119
+ break;
120
+ case 'COLOR_0':
121
+ name = 'colors';
122
+ break;
116
123
  }
117
124
  attributes[name] = device.createBuffer({data: attribute.value, id: `${attributeName}-buffer`});
118
125
  const {value, size, normalized} = attribute;
119
126
  bufferLayout.push({name, format: getVertexFormatFromAttribute(value, size, normalized)});
120
127
  }
121
128
 
122
- const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices)
129
+ const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices);
123
130
 
124
131
  return {attributes, bufferLayout, vertexCount};
125
132
  }
package/src/index.ts CHANGED
@@ -23,6 +23,7 @@ export type {TextureTransformProps} from './transform/texture-transform';
23
23
  export {TextureTransform} from './transform/texture-transform';
24
24
 
25
25
  export {PipelineFactory} from './lib/pipeline-factory';
26
+ export {ShaderFactory} from './lib/shader-factory';
26
27
 
27
28
  // Utils
28
29
  export {ClipSpace} from './lib/clip-space';
@@ -34,7 +35,7 @@ export type {ModelNodeProps} from './scenegraph/model-node';
34
35
  export {ModelNode} from './scenegraph/model-node';
35
36
 
36
37
  // Geometries
37
- export type {GeometryProps} from './geometry/geometry';
38
+ export type {GeometryProps, GeometryAttribute} from './geometry/geometry';
38
39
  export {Geometry} from './geometry/geometry';
39
40
  export type {GPUGeometryProps} from './geometry/gpu-geometry';
40
41
  export {GPUGeometry} from './geometry/gpu-geometry';
@@ -58,3 +59,5 @@ export {TruncatedConeGeometry} from './geometries/truncated-cone-geometry';
58
59
  // EXPERIMENTAL
59
60
  export type {ShaderModuleInputs} from './shader-inputs';
60
61
  export {ShaderInputs as _ShaderInputs} from './shader-inputs';
62
+ export type {ComputationProps} from './computation';
63
+ export {Computation} from './computation';
@@ -1,10 +1,10 @@
1
-
2
1
  // ClipSpace
3
2
  import {Device, glsl} from '@luma.gl/core';
4
3
  import {Model, ModelProps} from '../model/model';
5
4
  import {Geometry} from '../geometry/geometry';
6
5
 
7
6
  const CLIPSPACE_VERTEX_SHADER = glsl`\
7
+ #version 300 es
8
8
  in vec2 aClipSpacePosition;
9
9
  in vec2 aTexCoord;
10
10
  in vec2 aCoordinate;
@@ -28,25 +28,22 @@ const POSITIONS = [-1, -1, 1, -1, -1, 1, 1, 1];
28
28
  * A flat geometry that covers the "visible area" that the GPU renders.
29
29
  */
30
30
  export class ClipSpace extends Model {
31
- constructor(device: Device, opts?: ModelProps) {
32
- const TEX_COORDS = POSITIONS.map((coord) => (coord === -1 ? 0 : coord));
31
+ constructor(device: Device, opts: Omit<ModelProps, 'vs' | 'vertexCount' | 'geometry'>) {
32
+ const TEX_COORDS = POSITIONS.map(coord => (coord === -1 ? 0 : coord));
33
33
 
34
- super(
35
- device,
36
- {
37
- ...opts,
38
- vs: CLIPSPACE_VERTEX_SHADER,
34
+ super(device, {
35
+ ...opts,
36
+ vs: CLIPSPACE_VERTEX_SHADER,
37
+ vertexCount: 4,
38
+ geometry: new Geometry({
39
+ topology: 'triangle-strip',
39
40
  vertexCount: 4,
40
- geometry: new Geometry({
41
- topology: 'triangle-strip',
42
- vertexCount: 4,
43
- attributes: {
44
- aClipSpacePosition: {size: 2, value: new Float32Array(POSITIONS)},
45
- aTexCoord: {size: 2, value: new Float32Array(TEX_COORDS)},
46
- aCoordinate: {size: 2, value: new Float32Array(TEX_COORDS)}
47
- }
48
- })
49
- }
50
- );
41
+ attributes: {
42
+ aClipSpacePosition: {size: 2, value: new Float32Array(POSITIONS)},
43
+ aTexCoord: {size: 2, value: new Float32Array(TEX_COORDS)},
44
+ aCoordinate: {size: 2, value: new Float32Array(TEX_COORDS)}
45
+ }
46
+ })
47
+ });
51
48
  }
52
49
  }
@@ -1,33 +1,35 @@
1
- // luma.gl, MIT license
2
- import type {RenderPipelineProps} from '@luma.gl/core';
3
- import {Device, RenderPipeline} from '@luma.gl/core';
4
-
5
- /** Todo - should be same as RenderPipelineProps */
6
- export type PipelineFactoryProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
7
- // Only accepts string shaders
8
- vs: string;
9
- fs: string;
10
- };
11
-
12
- /**
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {RenderPipelineProps, ComputePipelineProps} from '@luma.gl/core';
6
+ import {Device, RenderPipeline, ComputePipeline} from '@luma.gl/core';
7
+
8
+ export type PipelineFactoryProps = RenderPipelineProps;
9
+
10
+ /**
13
11
  * Efficiently creates / caches pipelines
14
12
  */
15
13
  export class PipelineFactory {
16
- static defaultProps: Required<PipelineFactoryProps> = {
17
- ...RenderPipeline.defaultProps,
18
- vs: undefined!,
19
- fs: undefined!
20
- }
14
+ static defaultProps: Required<PipelineFactoryProps> = {...RenderPipeline.defaultProps};
21
15
 
22
16
  readonly device: Device;
23
17
 
24
18
  private _hashCounter: number = 0;
25
19
  private readonly _hashes: Record<string, number> = {};
26
- private readonly _useCounts: Record<string, number> = {};
27
- private readonly _pipelineCache: Record<string, RenderPipeline> = {};
28
-
20
+ private readonly _renderPipelineCache: Record<
21
+ string,
22
+ {pipeline: RenderPipeline; useCount: number}
23
+ > = {};
24
+ private readonly _computePipelineCache: Record<
25
+ string,
26
+ {pipeline: ComputePipeline; useCount: number}
27
+ > = {};
28
+
29
+ /** Get the singleton default pipeline factory for the specified device */
29
30
  static getDefaultPipelineFactory(device: Device): PipelineFactory {
30
- device._lumaData.defaultPipelineFactory = device._lumaData.defaultPipelineFactory || new PipelineFactory(device);
31
+ device._lumaData.defaultPipelineFactory =
32
+ device._lumaData.defaultPipelineFactory || new PipelineFactory(device);
31
33
  return device._lumaData.defaultPipelineFactory as PipelineFactory;
32
34
  }
33
35
 
@@ -35,83 +37,88 @@ export class PipelineFactory {
35
37
  this.device = device;
36
38
  }
37
39
 
38
- createRenderPipeline(options: PipelineFactoryProps): RenderPipeline {
39
- const props: Required<PipelineFactoryProps> = {...PipelineFactory.defaultProps, ...options};
40
+ /** Return a RenderPipeline matching props. Reuses a similar pipeline if already created. */
41
+ createRenderPipeline(props: RenderPipelineProps): RenderPipeline {
42
+ const allProps: Required<RenderPipelineProps> = {...RenderPipeline.defaultProps, ...props};
40
43
 
41
- const hash = this._hashRenderPipeline({...props});
44
+ const hash = this._hashRenderPipeline(allProps);
42
45
 
43
- if (!this._pipelineCache[hash]) {
46
+ if (!this._renderPipelineCache[hash]) {
44
47
  const pipeline = this.device.createRenderPipeline({
45
- ...props,
46
- vs: this.device.createShader({stage: 'vertex', source: props.vs}),
47
- fs: props.fs ? this.device.createShader({stage: 'fragment', source: props.fs}) : null,
48
+ ...allProps,
49
+ id: allProps.id ? `${allProps.id}-cached` : undefined
48
50
  });
49
-
50
51
  pipeline.hash = hash;
51
- this._pipelineCache[hash] = pipeline;
52
- this._useCounts[hash] = 0;
52
+ this._renderPipelineCache[hash] = {pipeline, useCount: 0};
53
53
  }
54
54
 
55
- this._useCounts[hash]++;
55
+ this._renderPipelineCache[hash].useCount++;
56
+ return this._renderPipelineCache[hash].pipeline;
57
+ }
58
+
59
+ createComputePipeline(props: ComputePipelineProps): ComputePipeline {
60
+ const allProps: Required<ComputePipelineProps> = {...ComputePipeline.defaultProps, ...props};
61
+
62
+ const hash = this._hashComputePipeline(allProps);
63
+
64
+ if (!this._computePipelineCache[hash]) {
65
+ const pipeline = this.device.createComputePipeline({
66
+ ...allProps,
67
+ id: allProps.id ? `${allProps.id}-cached` : undefined
68
+ });
69
+ pipeline.hash = hash;
70
+ this._computePipelineCache[hash] = {pipeline, useCount: 0};
71
+ }
56
72
 
57
- return this._pipelineCache[hash];
73
+ this._computePipelineCache[hash].useCount++;
74
+ return this._computePipelineCache[hash].pipeline;
58
75
  }
59
76
 
60
- release(pipeline: RenderPipeline): void {
77
+ release(pipeline: RenderPipeline | ComputePipeline): void {
61
78
  const hash = pipeline.hash;
62
- this._useCounts[hash]--;
63
- if (this._useCounts[hash] === 0) {
64
- this._pipelineCache[hash].destroy();
65
- delete this._pipelineCache[hash];
66
- delete this._useCounts[hash];
79
+ const cache =
80
+ pipeline instanceof ComputePipeline ? this._computePipelineCache : this._renderPipelineCache;
81
+ cache[hash].useCount--;
82
+ if (cache[hash].useCount === 0) {
83
+ cache[hash].pipeline.destroy();
84
+ delete cache[hash];
67
85
  }
68
86
  }
69
87
 
70
88
  // PRIVATE
71
-
72
- _createRenderPipeline(props: PipelineFactoryProps): RenderPipeline {
73
- if (!props.fs) {
74
- throw new Error('fs');
75
- }
76
-
77
- const pipeline = this.device.createRenderPipeline({
78
- ...props,
79
- vs: this.device.createShader({stage: 'vertex', source: props.vs}),
80
- fs: props.fs ? this.device.createShader({stage: 'fragment', source: props.fs}) : null,
81
- });
82
-
83
- return pipeline;
89
+ private _hashComputePipeline(props: ComputePipelineProps): string {
90
+ const shaderHash = this._getHash(props.shader.source);
91
+ return `${shaderHash}`;
84
92
  }
85
93
 
86
94
  /** Calculate a hash based on all the inputs for a render pipeline */
87
- _hashRenderPipeline(props: PipelineFactoryProps): string {
88
- const vsHash = this._getHash(props.vs);
89
- const fsHash = props.fs ? this._getHash(props.fs) : 0;
95
+ private _hashRenderPipeline(props: RenderPipelineProps): string {
96
+ const vsHash = this._getHash(props.vs.source);
97
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
90
98
 
91
99
  // WebGL specific
92
100
  // const {varyings = [], bufferMode = {}} = props;
93
101
  // const varyingHashes = varyings.map((v) => this._getHash(v));
94
102
  const varyingHash = '-'; // `${varyingHashes.join('/')}B${bufferMode}`
103
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
95
104
 
96
- switch (this.device.info.type) {
97
- case 'webgpu':
105
+ switch (this.device.type) {
106
+ // case 'webgl':
107
+ // WebGL is more dynamic
108
+ // return `${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
109
+ default:
98
110
  // On WebGPU we need to rebuild the pipeline if topology, parameters or bufferLayout change
99
111
  const parameterHash = this._getHash(JSON.stringify(props.parameters));
100
- const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
101
112
  // TODO - Can json.stringify() generate different strings for equivalent objects if order of params is different?
102
113
  // create a deepHash() to deduplicate?
103
- return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}}`;
104
- default:
105
- // WebGL is more dynamic
106
- return `${vsHash}/${fsHash}V${varyingHash}`;
114
+ return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
107
115
  }
108
116
  }
109
117
 
110
- _getHash(key: string): number {
118
+ private _getHash(key: string): number {
111
119
  if (this._hashes[key] === undefined) {
112
120
  this._hashes[key] = this._hashCounter++;
113
121
  }
114
122
  return this._hashes[key];
115
123
  }
116
124
  }
117
-
@@ -0,0 +1,57 @@
1
+ import {Device, Shader, ShaderProps} from '@luma.gl/core';
2
+
3
+ /** Manages a cached pool of Shaders for reuse. */
4
+ export class ShaderFactory {
5
+ static readonly defaultProps: Required<ShaderProps> = {...Shader.defaultProps};
6
+
7
+ public readonly device: Device;
8
+
9
+ private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
10
+
11
+ /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
12
+ static getDefaultShaderFactory(device: Device): ShaderFactory {
13
+ device._lumaData.defaultShaderFactory ||= new ShaderFactory(device);
14
+ return device._lumaData.defaultShaderFactory as ShaderFactory;
15
+ }
16
+
17
+ /** @internal */
18
+ constructor(device: Device) {
19
+ this.device = device;
20
+ }
21
+
22
+ /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
23
+ createShader(props: ShaderProps): Shader {
24
+ const key = this._hashShader(props);
25
+
26
+ let cacheEntry = this._cache[key];
27
+ if (!cacheEntry) {
28
+ const shader = this.device.createShader({
29
+ ...props,
30
+ id: props.id ? `${props.id}-cached` : undefined
31
+ });
32
+ this._cache[key] = cacheEntry = {shader, useCount: 0};
33
+ }
34
+
35
+ cacheEntry.useCount++;
36
+ return cacheEntry.shader;
37
+ }
38
+
39
+ /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
40
+ release(shader: Shader): void {
41
+ const key = this._hashShader(shader);
42
+ const cacheEntry = this._cache[key];
43
+ if (cacheEntry) {
44
+ cacheEntry.useCount--;
45
+ if (cacheEntry.useCount === 0) {
46
+ delete this._cache[key];
47
+ cacheEntry.shader.destroy();
48
+ }
49
+ }
50
+ }
51
+
52
+ // PRIVATE
53
+
54
+ private _hashShader(value: Shader | ShaderProps): string {
55
+ return `${value.stage}:${value.source}`;
56
+ }
57
+ }