@luma.gl/engine 9.0.0-alpha.9 → 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 (187) hide show
  1. package/LICENSE +3 -1
  2. package/dist/animation/key-frames.d.ts +1 -1
  3. package/dist/animation/key-frames.d.ts.map +1 -1
  4. package/dist/animation/key-frames.js +51 -72
  5. package/dist/animation/timeline.d.ts +8 -8
  6. package/dist/animation/timeline.d.ts.map +1 -1
  7. package/dist/animation/timeline.js +95 -131
  8. package/dist/animation-loop/animation-loop-template.d.ts +23 -0
  9. package/dist/animation-loop/animation-loop-template.d.ts.map +1 -0
  10. package/dist/animation-loop/animation-loop-template.js +21 -0
  11. package/dist/{lib → animation-loop}/animation-loop.d.ts +31 -23
  12. package/dist/animation-loop/animation-loop.d.ts.map +1 -0
  13. package/dist/animation-loop/animation-loop.js +442 -0
  14. package/dist/{lib → animation-loop}/animation-props.d.ts +4 -5
  15. package/dist/animation-loop/animation-props.d.ts.map +1 -0
  16. package/dist/animation-loop/animation-props.js +1 -0
  17. package/dist/animation-loop/make-animation-loop.d.ts +6 -0
  18. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -0
  19. package/dist/animation-loop/make-animation-loop.js +32 -0
  20. package/dist/computation.d.ts +95 -0
  21. package/dist/computation.d.ts.map +1 -0
  22. package/dist/computation.js +248 -0
  23. package/dist/debug/copy-texture-to-image.d.ts +26 -0
  24. package/dist/debug/copy-texture-to-image.d.ts.map +1 -0
  25. package/dist/debug/copy-texture-to-image.js +43 -0
  26. package/dist/debug/debug-framebuffer.d.ts +11 -0
  27. package/dist/debug/debug-framebuffer.d.ts.map +1 -0
  28. package/dist/debug/debug-framebuffer.js +46 -0
  29. package/dist/debug/debug-shader-layout.d.ts +9 -0
  30. package/dist/debug/debug-shader-layout.d.ts.map +1 -0
  31. package/dist/debug/debug-shader-layout.js +27 -0
  32. package/dist/debug/pixel-data-utils.d.ts +24 -0
  33. package/dist/debug/pixel-data-utils.d.ts.map +1 -0
  34. package/dist/debug/pixel-data-utils.js +39 -0
  35. package/dist/dist.dev.js +9592 -0
  36. package/dist/dist.min.js +102 -0
  37. package/dist/geometries/cone-geometry.d.ts +2 -2
  38. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  39. package/dist/geometries/cone-geometry.js +13 -18
  40. package/dist/geometries/cube-geometry.d.ts +2 -2
  41. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  42. package/dist/geometries/cube-geometry.js +192 -57
  43. package/dist/geometries/cylinder-geometry.d.ts +2 -2
  44. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  45. package/dist/geometries/cylinder-geometry.js +11 -15
  46. package/dist/geometries/ico-sphere-geometry.d.ts +2 -2
  47. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  48. package/dist/geometries/ico-sphere-geometry.js +143 -171
  49. package/dist/geometries/plane-geometry.d.ts +2 -2
  50. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  51. package/dist/geometries/plane-geometry.js +95 -122
  52. package/dist/geometries/sphere-geometry.d.ts +2 -2
  53. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  54. package/dist/geometries/sphere-geometry.js +78 -101
  55. package/dist/geometries/truncated-cone-geometry.d.ts +2 -4
  56. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  57. package/dist/geometries/truncated-cone-geometry.js +100 -134
  58. package/dist/geometry/geometry-table.d.ts +2 -2
  59. package/dist/geometry/geometry-table.d.ts.map +1 -1
  60. package/dist/geometry/geometry-table.js +3 -1
  61. package/dist/geometry/geometry-utils.d.ts.map +1 -1
  62. package/dist/geometry/geometry-utils.js +35 -41
  63. package/dist/geometry/geometry.d.ts +43 -43
  64. package/dist/geometry/geometry.d.ts.map +1 -1
  65. package/dist/geometry/geometry.js +82 -139
  66. package/dist/geometry/gpu-geometry.d.ts +37 -0
  67. package/dist/geometry/gpu-geometry.d.ts.map +1 -0
  68. package/dist/geometry/gpu-geometry.js +90 -0
  69. package/dist/geometry/gpu-table.d.ts +1 -0
  70. package/dist/geometry/gpu-table.d.ts.map +1 -0
  71. package/dist/geometry/gpu-table.js +42 -0
  72. package/dist/index.cjs +3444 -0
  73. package/dist/index.cjs.map +7 -0
  74. package/dist/index.d.ts +43 -24
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +29 -15
  77. package/dist/lib/clip-space.d.ts +8 -0
  78. package/dist/lib/clip-space.d.ts.map +1 -1
  79. package/dist/lib/clip-space.js +43 -2
  80. package/dist/lib/pipeline-factory.d.ts +17 -51
  81. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  82. package/dist/lib/pipeline-factory.js +84 -209
  83. package/dist/lib/shader-factory.d.ts +17 -0
  84. package/dist/lib/shader-factory.d.ts.map +1 -0
  85. package/dist/lib/shader-factory.js +46 -0
  86. package/dist/model/model.d.ts +219 -0
  87. package/dist/model/model.d.ts.map +1 -0
  88. package/dist/model/model.js +659 -0
  89. package/dist/scenegraph/group-node.d.ts +21 -0
  90. package/dist/scenegraph/group-node.d.ts.map +1 -0
  91. package/dist/scenegraph/group-node.js +84 -0
  92. package/dist/scenegraph/model-node.d.ts +18 -0
  93. package/dist/scenegraph/model-node.d.ts.map +1 -0
  94. package/dist/scenegraph/model-node.js +35 -0
  95. package/dist/scenegraph/scenegraph-node.d.ts +56 -0
  96. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -0
  97. package/dist/scenegraph/scenegraph-node.js +153 -0
  98. package/dist/shader-inputs.d.ts +63 -0
  99. package/dist/shader-inputs.d.ts.map +1 -0
  100. package/dist/shader-inputs.js +107 -0
  101. package/dist/transform/buffer-transform.d.ts +35 -0
  102. package/dist/transform/buffer-transform.d.ts.map +1 -0
  103. package/dist/transform/buffer-transform.js +70 -0
  104. package/dist/transform/texture-transform.d.ts +57 -0
  105. package/dist/transform/texture-transform.d.ts.map +1 -0
  106. package/dist/transform/texture-transform.js +117 -0
  107. package/dist.min.js +25 -0
  108. package/package.json +24 -14
  109. package/src/animation/timeline.ts +35 -34
  110. package/src/animation-loop/animation-loop-template.ts +25 -0
  111. package/src/{lib → animation-loop}/animation-loop.ts +114 -93
  112. package/src/{lib → animation-loop}/animation-props.ts +2 -2
  113. package/src/animation-loop/make-animation-loop.ts +53 -0
  114. package/src/computation.ts +346 -0
  115. package/src/debug/copy-texture-to-image.ts +70 -0
  116. package/src/debug/debug-framebuffer.ts +70 -0
  117. package/src/debug/debug-shader-layout.ts +38 -0
  118. package/src/debug/pixel-data-utils.ts +54 -0
  119. package/src/geometries/cone-geometry.ts +1 -1
  120. package/src/geometries/cube-geometry.ts +62 -56
  121. package/src/geometries/cylinder-geometry.ts +2 -2
  122. package/src/geometries/ico-sphere-geometry.ts +6 -5
  123. package/src/geometries/plane-geometry.ts +5 -4
  124. package/src/geometries/sphere-geometry.ts +4 -3
  125. package/src/geometries/truncated-cone-geometry.ts +6 -14
  126. package/src/geometry/geometry-table.ts +10 -7
  127. package/src/geometry/geometry-utils.ts +19 -3
  128. package/src/geometry/geometry.ts +68 -110
  129. package/src/geometry/gpu-geometry.ts +132 -0
  130. package/src/geometry/gpu-table.ts +41 -0
  131. package/src/index.ts +37 -10
  132. package/src/lib/clip-space.ts +32 -34
  133. package/src/lib/pipeline-factory.ts +83 -193
  134. package/src/lib/shader-factory.ts +57 -0
  135. package/src/model/model.ts +835 -0
  136. package/src/scenegraph/group-node.ts +107 -0
  137. package/src/scenegraph/model-node.ts +50 -0
  138. package/src/scenegraph/scenegraph-node.ts +204 -0
  139. package/src/shader-inputs.ts +157 -0
  140. package/src/transform/buffer-transform.ts +102 -0
  141. package/src/transform/texture-transform.ts +168 -0
  142. package/dist/animation/key-frames.js.map +0 -1
  143. package/dist/animation/timeline.js.map +0 -1
  144. package/dist/bundle.d.ts +0 -2
  145. package/dist/bundle.d.ts.map +0 -1
  146. package/dist/bundle.js +0 -5
  147. package/dist/bundle.js.map +0 -1
  148. package/dist/geometries/cone-geometry.js.map +0 -1
  149. package/dist/geometries/cube-geometry.js.map +0 -1
  150. package/dist/geometries/cylinder-geometry.js.map +0 -1
  151. package/dist/geometries/ico-sphere-geometry.js.map +0 -1
  152. package/dist/geometries/plane-geometry.js.map +0 -1
  153. package/dist/geometries/sphere-geometry.js.map +0 -1
  154. package/dist/geometries/truncated-cone-geometry.js.map +0 -1
  155. package/dist/geometry/geometry-table.js.map +0 -1
  156. package/dist/geometry/geometry-utils.js.map +0 -1
  157. package/dist/geometry/geometry.js.map +0 -1
  158. package/dist/geometry/primitive-utils.d.ts +0 -1
  159. package/dist/geometry/primitive-utils.d.ts.map +0 -1
  160. package/dist/geometry/primitive-utils.js +0 -2
  161. package/dist/geometry/primitive-utils.js.map +0 -1
  162. package/dist/index.js.map +0 -1
  163. package/dist/lib/animation-loop.d.ts.map +0 -1
  164. package/dist/lib/animation-loop.js +0 -480
  165. package/dist/lib/animation-loop.js.map +0 -1
  166. package/dist/lib/animation-props.d.ts.map +0 -1
  167. package/dist/lib/animation-props.js +0 -2
  168. package/dist/lib/animation-props.js.map +0 -1
  169. package/dist/lib/clip-space.js.map +0 -1
  170. package/dist/lib/model-utils.d.ts +0 -5
  171. package/dist/lib/model-utils.d.ts.map +0 -1
  172. package/dist/lib/model-utils.js +0 -45
  173. package/dist/lib/model-utils.js.map +0 -1
  174. package/dist/lib/model.d.ts +0 -41
  175. package/dist/lib/model.d.ts.map +0 -1
  176. package/dist/lib/model.js +0 -182
  177. package/dist/lib/model.js.map +0 -1
  178. package/dist/lib/pipeline-factory.js.map +0 -1
  179. package/dist/lib/render-loop.d.ts +0 -14
  180. package/dist/lib/render-loop.d.ts.map +0 -1
  181. package/dist/lib/render-loop.js +0 -49
  182. package/dist/lib/render-loop.js.map +0 -1
  183. package/src/bundle.ts +0 -4
  184. package/src/geometry/primitive-utils.ts +0 -30
  185. package/src/lib/model-utils.ts +0 -124
  186. package/src/lib/model.ts +0 -183
  187. package/src/lib/render-loop.ts +0 -58
@@ -0,0 +1,132 @@
1
+ import type {PrimitiveTopology, BufferLayout} from '@luma.gl/core';
2
+ import {Device, Buffer, uid, assert, getVertexFormatFromAttribute} from '@luma.gl/core';
3
+ import type {Geometry} from '../geometry/geometry';
4
+
5
+ export type GPUGeometryProps = {
6
+ id?: string;
7
+ /** Determines how vertices are read from the 'vertex' attributes */
8
+ topology:
9
+ | 'point-list'
10
+ | 'line-list'
11
+ | 'line-strip'
12
+ | 'line-loop-webgl'
13
+ | 'triangle-list'
14
+ | 'triangle-strip'
15
+ | 'triangle-fan-webgl';
16
+ /** Auto calculated from attributes if not provided */
17
+ vertexCount: number;
18
+ bufferLayout: BufferLayout[];
19
+ indices?: Buffer | null;
20
+ attributes: Record<string, Buffer>;
21
+ };
22
+
23
+ export class GPUGeometry {
24
+ readonly id: string;
25
+ userData: Record<string, unknown> = {};
26
+
27
+ /** Determines how vertices are read from the 'vertex' attributes */
28
+ readonly topology?: PrimitiveTopology;
29
+ readonly bufferLayout: BufferLayout[] = [];
30
+
31
+ readonly vertexCount: number;
32
+ readonly indices?: Buffer | null;
33
+ readonly attributes: Record<string, Buffer>;
34
+
35
+ constructor(props: GPUGeometryProps) {
36
+ this.id = props.id || uid('geometry');
37
+ this.topology = props.topology;
38
+ this.indices = props.indices || null;
39
+ this.attributes = props.attributes;
40
+
41
+ this.vertexCount = props.vertexCount;
42
+
43
+ this.bufferLayout = props.bufferLayout || [];
44
+
45
+ if (this.indices) {
46
+ assert(this.indices.usage === Buffer.INDEX);
47
+ }
48
+ }
49
+
50
+ destroy(): void {
51
+ this.indices?.destroy();
52
+ for (const attribute of Object.values(this.attributes)) {
53
+ attribute.destroy();
54
+ }
55
+ }
56
+
57
+ getVertexCount(): number {
58
+ return this.vertexCount;
59
+ }
60
+
61
+ getAttributes(): Record<string, Buffer> {
62
+ return this.attributes;
63
+ }
64
+
65
+ getIndexes(): Buffer | null {
66
+ return this.indices;
67
+ }
68
+
69
+ _calculateVertexCount(positions: Buffer): number {
70
+ // Assume that positions is a fully packed float32x3 buffer
71
+ const vertexCount = positions.byteLength / 12;
72
+ return vertexCount;
73
+ }
74
+ }
75
+
76
+ export function makeGPUGeometry(device: Device, geometry: Geometry | GPUGeometry): GPUGeometry {
77
+ if (geometry instanceof GPUGeometry) {
78
+ return geometry;
79
+ }
80
+
81
+ const indices = getIndexBufferFromGeometry(device, geometry);
82
+ const {attributes, bufferLayout} = getAttributeBuffersFromGeometry(device, geometry);
83
+ return new GPUGeometry({
84
+ topology: geometry.topology || 'triangle-list',
85
+ bufferLayout,
86
+ vertexCount: geometry.vertexCount,
87
+ indices,
88
+ attributes
89
+ });
90
+ }
91
+
92
+ export function getIndexBufferFromGeometry(device: Device, geometry: Geometry): Buffer | undefined {
93
+ if (!geometry.indices) {
94
+ return undefined;
95
+ }
96
+ const data = geometry.indices.value;
97
+ return device.createBuffer({usage: Buffer.INDEX, data});
98
+ }
99
+
100
+ export function getAttributeBuffersFromGeometry(
101
+ device: Device,
102
+ geometry: Geometry
103
+ ): {attributes: Record<string, Buffer>; bufferLayout: BufferLayout[]; vertexCount: number} {
104
+ const bufferLayout: BufferLayout[] = [];
105
+
106
+ const attributes: Record<string, Buffer> = {};
107
+ for (const [attributeName, attribute] of Object.entries(geometry.attributes)) {
108
+ let name: string = attributeName;
109
+ // TODO Map some GLTF attribute names (is this still needed?)
110
+ switch (attributeName) {
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;
123
+ }
124
+ attributes[name] = device.createBuffer({data: attribute.value, id: `${attributeName}-buffer`});
125
+ const {value, size, normalized} = attribute;
126
+ bufferLayout.push({name, format: getVertexFormatFromAttribute(value, size, normalized)});
127
+ }
128
+
129
+ const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices);
130
+
131
+ return {attributes, bufferLayout, vertexCount};
132
+ }
@@ -0,0 +1,41 @@
1
+ /*
2
+ export function getAttributeLayoutsFromGeometry(geometry: Geometry) {
3
+ const layouts: Record<string, {}> = {};
4
+ let indices = geometry.indices;
5
+
6
+ for (const [name, attribute] of Object.entries(geometry.attributes)) {
7
+ const remappedName = mapAttributeName(name);
8
+
9
+ if (attribute.constant) {
10
+ throw new Error('constant attributes not supported');
11
+ } else {
12
+ const typedArray = attribute.value;
13
+ // Create accessor by copying the attribute and removing `value``
14
+ const accessor = {...attribute};
15
+ delete accessor.value;
16
+ buffers[remappedName] = [device.createBuffer(typedArray), accessor];
17
+
18
+ inferAttributeAccessor(name, accessor);
19
+ }
20
+ }
21
+ }
22
+
23
+ export class Table {
24
+ length: number;
25
+ // columns: Record<string, TypedArray> = {};
26
+ }
27
+
28
+ export class GPUTable {
29
+ length: number;
30
+ columns: Record<string, Buffer> = {};
31
+ }
32
+
33
+ export function convertTableToGPUTable(table: Table) {
34
+ // for (const ) {}
35
+ }
36
+
37
+ export function renameTableColumns(table: Table, map: (name: string) => string) {
38
+ const newColumns = table.columns.reduce()
39
+ table.clone();
40
+ }
41
+ */
package/src/index.ts CHANGED
@@ -1,22 +1,44 @@
1
1
  // luma.gl Engine API
2
- export type {AnimationProps} from './lib/animation-props';
3
- export type {AnimationLoopProps} from './lib/animation-loop';
4
- export {AnimationLoop} from './lib/animation-loop';
5
- export {RenderLoop} from './lib/render-loop';
6
- export type {ModelProps} from './lib/model';
7
- export {default as Model} from './lib/model';
8
-
9
- export {PipelineFactory} from './lib/pipeline-factory';
10
2
 
11
3
  // Animation
12
4
  export {Timeline} from './animation/timeline';
13
5
  export {KeyFrames} from './animation/key-frames';
6
+ export type {AnimationProps} from './animation-loop/animation-props';
7
+
8
+ export {AnimationLoopTemplate} from './animation-loop/animation-loop-template';
9
+
10
+ export type {AnimationLoopProps} from './animation-loop/animation-loop';
11
+ export {AnimationLoop} from './animation-loop/animation-loop';
12
+
13
+ export type {MakeAnimationLoopProps} from './animation-loop/make-animation-loop';
14
+ export {makeAnimationLoop} from './animation-loop/make-animation-loop';
15
+
16
+ export type {ModelProps} from './model/model';
17
+ export {Model} from './model/model';
18
+
19
+ // Transforms
20
+ export type {BufferTransformProps} from './transform/buffer-transform';
21
+ export {BufferTransform} from './transform/buffer-transform';
22
+ export type {TextureTransformProps} from './transform/texture-transform';
23
+ export {TextureTransform} from './transform/texture-transform';
24
+
25
+ export {PipelineFactory} from './lib/pipeline-factory';
26
+ export {ShaderFactory} from './lib/shader-factory';
14
27
 
15
28
  // Utils
16
- // export {default as ClipSpace} from './lib/clip-space';
29
+ export {ClipSpace} from './lib/clip-space';
30
+
31
+ // Scenegraph Core nodes
32
+ export {ScenegraphNode} from './scenegraph/scenegraph-node';
33
+ export {GroupNode} from './scenegraph/group-node';
34
+ export type {ModelNodeProps} from './scenegraph/model-node';
35
+ export {ModelNode} from './scenegraph/model-node';
17
36
 
18
37
  // Geometries
19
- export {default as Geometry} from './geometry/geometry';
38
+ export type {GeometryProps, GeometryAttribute} from './geometry/geometry';
39
+ export {Geometry} from './geometry/geometry';
40
+ export type {GPUGeometryProps} from './geometry/gpu-geometry';
41
+ export {GPUGeometry} from './geometry/gpu-geometry';
20
42
 
21
43
  // Primitives
22
44
  export type {ConeGeometryProps} from './geometries/cone-geometry';
@@ -34,3 +56,8 @@ export {SphereGeometry} from './geometries/sphere-geometry';
34
56
  export type {TruncatedConeGeometryProps} from './geometries/truncated-cone-geometry';
35
57
  export {TruncatedConeGeometry} from './geometries/truncated-cone-geometry';
36
58
 
59
+ // EXPERIMENTAL
60
+ export type {ShaderModuleInputs} from './shader-inputs';
61
+ export {ShaderInputs as _ShaderInputs} from './shader-inputs';
62
+ export type {ComputationProps} from './computation';
63
+ export {Computation} from './computation';
@@ -1,18 +1,17 @@
1
-
2
1
  // ClipSpace
3
- /*
4
- import GL from '@luma.gl/constants';
5
- import Model, {ModelProps} from './model';
6
- import Geometry from '../geometry/geometry';
2
+ import {Device, glsl} from '@luma.gl/core';
3
+ import {Model, ModelProps} from '../model/model';
4
+ import {Geometry} from '../geometry/geometry';
7
5
 
8
- const CLIPSPACE_VERTEX_SHADER = `\
9
- attribute vec2 aClipSpacePosition;
10
- attribute vec2 aTexCoord;
11
- attribute vec2 aCoordinate;
6
+ const CLIPSPACE_VERTEX_SHADER = glsl`\
7
+ #version 300 es
8
+ in vec2 aClipSpacePosition;
9
+ in vec2 aTexCoord;
10
+ in vec2 aCoordinate;
12
11
 
13
- varying vec2 position;
14
- varying vec2 coordinate;
15
- varying vec2 uv;
12
+ out vec2 position;
13
+ out vec2 coordinate;
14
+ out vec2 uv;
16
15
 
17
16
  void main(void) {
18
17
  gl_Position = vec4(aClipSpacePosition, 0., 1.);
@@ -22,30 +21,29 @@ void main(void) {
22
21
  }
23
22
  `;
24
23
 
25
- /* eslint-disable indent, no-multi-spaces *
24
+ /* eslint-disable indent, no-multi-spaces */
26
25
  const POSITIONS = [-1, -1, 1, -1, -1, 1, 1, 1];
27
26
 
28
-
29
- export default class ClipSpace extends Model {
30
- constructor(gl: WebGLRenderingContext, opts?: ModelProps) {
31
- const TEX_COORDS = POSITIONS.map((coord) => (coord === -1 ? 0 : coord));
32
-
33
- super(
34
- gl,
35
- Object.assign({}, opts, {
36
- vs: CLIPSPACE_VERTEX_SHADER,
37
- geometry: new Geometry({
38
- drawMode: GL.TRIANGLE_STRIP,
39
- vertexCount: 4,
40
- attributes: {
41
- aClipSpacePosition: {size: 2, value: new Float32Array(POSITIONS)},
42
- aTexCoord: {size: 2, value: new Float32Array(TEX_COORDS)},
43
- aCoordinate: {size: 2, value: new Float32Array(TEX_COORDS)}
44
- }
45
- })
27
+ /**
28
+ * A flat geometry that covers the "visible area" that the GPU renders.
29
+ */
30
+ export class ClipSpace extends Model {
31
+ constructor(device: Device, opts: Omit<ModelProps, 'vs' | 'vertexCount' | 'geometry'>) {
32
+ const TEX_COORDS = POSITIONS.map(coord => (coord === -1 ? 0 : coord));
33
+
34
+ super(device, {
35
+ ...opts,
36
+ vs: CLIPSPACE_VERTEX_SHADER,
37
+ vertexCount: 4,
38
+ geometry: new Geometry({
39
+ topology: 'triangle-strip',
40
+ vertexCount: 4,
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
46
  })
47
- );
48
- this.setVertexCount(4);
47
+ });
49
48
  }
50
49
  }
51
- */
@@ -1,234 +1,124 @@
1
- import type {RenderPipelineProps, RenderPipelineParameters, PrimitiveTopology, ShaderLayout} from '@luma.gl/api';
2
- import {Device, RenderPipeline, ComputePipeline} from '@luma.gl/api/';
3
- import type { ShaderModule } from '@luma.gl/shadertools';
4
- import {assembleShaders} from '@luma.gl/shadertools';
5
-
6
- export type GetRenderPipelineOptions = {
7
- vs: string;
8
- fs: string | null;
9
- topology: PrimitiveTopology;
10
- layout?: ShaderLayout | null;
11
- parameters?: RenderPipelineParameters;
12
-
13
- modules?: ShaderModule[];
14
- defines?: Record<string, string | number | boolean>;
15
- inject?: Record<string, string>;
16
- transpileToGLSL100?: boolean;
17
-
18
- varyings?: string[];
19
- bufferMode?: number,
20
- };
21
-
22
- export type GetComputePipelineOptions = {
23
- cs: string;
24
- parameters?: RenderPipelineParameters;
25
-
26
- modules?: ShaderModule[];
27
- defines?: Record<string, string>;
28
- inject?: Record<string, string>;
29
- transpileToGLSL100?: boolean;
30
-
31
- varyings?: string[];
32
- bufferMode?: number;
33
- };
34
-
35
- const DEFAULT_RENDER_PIPELINE_OPTIONS: Required<GetRenderPipelineOptions> = {
36
- vs: '',
37
- fs: '',
38
- modules: [],
39
- defines: {},
40
- inject: {},
41
- transpileToGLSL100: false,
42
- layout: null,
43
-
44
- varyings: [],
45
- bufferMode: 0x8c8d, // // varyings/bufferMode for xform feedback, 0x8c8d: SEPARATE_ATTRIBS
46
- topology: 'triangle-list',
47
- parameters: {}
48
- };
49
-
50
- type GetUniformsFunc = (props?: Record<string, any>) => Record<string, any>;
51
-
52
- /** Efficiently create shared pipelines with varying parameters */
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
+ /**
11
+ * Efficiently creates / caches pipelines
12
+ */
53
13
  export class PipelineFactory {
14
+ static defaultProps: Required<PipelineFactoryProps> = {...RenderPipeline.defaultProps};
15
+
54
16
  readonly device: Device;
55
17
 
56
- stateHash: number = 0; // Used to change hashing if hooks are modified
57
18
  private _hashCounter: number = 0;
58
19
  private readonly _hashes: Record<string, number> = {};
59
- private readonly _useCounts: Record<string, number> = {};
60
-
61
- private readonly _pipelineCache: Record<string, RenderPipeline> = {};
62
-
63
- private readonly _getUniforms: Record<string, GetUniformsFunc> = {};
64
- private readonly _hookFunctions: any[] = [];
65
- private _defaultModules: any[] = [];
66
- // private readonly _registeredModules = {}; // TODO: Remove? This isn't used anywhere in luma.gl
67
-
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 */
68
30
  static getDefaultPipelineFactory(device: Device): PipelineFactory {
69
- // @ts-expect-error Add to device
70
- device.defaultPipelineFactory = device.defaultPipelineFactory || new PipelineFactory(device);
71
- // @ts-expect-error Add to device
72
- return device.defaultPipelineFactory;
31
+ device._lumaData.defaultPipelineFactory =
32
+ device._lumaData.defaultPipelineFactory || new PipelineFactory(device);
33
+ return device._lumaData.defaultPipelineFactory as PipelineFactory;
73
34
  }
74
35
 
75
36
  constructor(device: Device) {
76
37
  this.device = device;
77
38
  }
78
39
 
79
- addDefaultModule(module: ShaderModule): void {
80
- if (!this._defaultModules.find((m) => m.name === (typeof module === 'string' ? module : module.name))) {
81
- this._defaultModules.push(module);
82
- }
83
- this.stateHash++;
84
- }
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};
85
43
 
86
- removeDefaultModule(module: ShaderModule): void {
87
- const moduleName = typeof module === 'string' ? module : module.name;
88
- this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
89
- this.stateHash++;
90
- }
44
+ const hash = this._hashRenderPipeline(allProps);
91
45
 
92
- addShaderHook(hook, opts?): void {
93
- if (opts) {
94
- hook = Object.assign(opts, {hook});
46
+ if (!this._renderPipelineCache[hash]) {
47
+ const pipeline = this.device.createRenderPipeline({
48
+ ...allProps,
49
+ id: allProps.id ? `${allProps.id}-cached` : undefined
50
+ });
51
+ pipeline.hash = hash;
52
+ this._renderPipelineCache[hash] = {pipeline, useCount: 0};
95
53
  }
96
- this._hookFunctions.push(hook);
97
- this.stateHash++;
98
- }
99
54
 
100
- createRenderPipeline(options: GetRenderPipelineOptions): {
101
- pipeline: RenderPipeline;
102
- getUniforms: GetUniformsFunc;
103
- } {
104
- const props: Required<GetRenderPipelineOptions> = {...DEFAULT_RENDER_PIPELINE_OPTIONS, ...options};
55
+ this._renderPipelineCache[hash].useCount++;
56
+ return this._renderPipelineCache[hash].pipeline;
57
+ }
105
58
 
106
- const modules = this._getModuleList(props.modules); // Combine with default modules
59
+ createComputePipeline(props: ComputePipelineProps): ComputePipeline {
60
+ const allProps: Required<ComputePipelineProps> = {...ComputePipeline.defaultProps, ...props};
107
61
 
108
- const hash = this._hashRenderPipeline({...props, modules});
62
+ const hash = this._hashComputePipeline(allProps);
109
63
 
110
- if (!this._pipelineCache[hash]) {
111
- const {pipeline, getUniforms} = this._createRenderPipeline({...props, modules});
64
+ if (!this._computePipelineCache[hash]) {
65
+ const pipeline = this.device.createComputePipeline({
66
+ ...allProps,
67
+ id: allProps.id ? `${allProps.id}-cached` : undefined
68
+ });
112
69
  pipeline.hash = hash;
113
- this._pipelineCache[hash] = pipeline;
114
- this._getUniforms[hash] = getUniforms || ((x?: unknown) => ({}));
115
- this._useCounts[hash] = 0;
70
+ this._computePipelineCache[hash] = {pipeline, useCount: 0};
116
71
  }
117
72
 
118
- this._useCounts[hash]++;
119
-
120
- return {
121
- pipeline: this._pipelineCache[hash],
122
- getUniforms: this._getUniforms[hash]
123
- };
73
+ this._computePipelineCache[hash].useCount++;
74
+ return this._computePipelineCache[hash].pipeline;
124
75
  }
125
76
 
126
- release(pipeline: RenderPipeline): void {
77
+ release(pipeline: RenderPipeline | ComputePipeline): void {
127
78
  const hash = pipeline.hash;
128
- this._useCounts[hash]--;
129
- if (this._useCounts[hash] === 0) {
130
- this._pipelineCache[hash].destroy();
131
- delete this._pipelineCache[hash];
132
- delete this._getUniforms[hash];
133
- 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];
134
85
  }
135
86
  }
136
87
 
137
- getUniforms(pipeline: RenderPipeline) {
138
- return this._getUniforms[pipeline.hash] || null;
139
- }
140
-
141
88
  // PRIVATE
142
-
143
- _createRenderPipeline(props: GetRenderPipelineOptions): {
144
- pipeline: RenderPipeline,
145
- getUniforms: GetUniformsFunc
146
- } {
147
- const platformInfo = {
148
- gpu: this.device.info.gpu,
149
- features: this.device.features
150
- };
151
-
152
- if (!props.fs) {
153
- throw new Error('fs');
154
- }
155
-
156
- const assembled = assembleShaders(platformInfo, {...props, fs: props.fs, hookFunctions: this._hookFunctions});
157
-
158
- const pipeline = this.device.createRenderPipeline({
159
- ...props,
160
- vs: this.device.createShader({stage: 'vertex', source: assembled.vs}),
161
- fs: assembled.fs ? this.device.createShader({stage: 'fragment', source: assembled.fs}) : null,
162
- });
163
-
164
- return {pipeline, getUniforms: assembled.getUniforms};
89
+ private _hashComputePipeline(props: ComputePipelineProps): string {
90
+ const shaderHash = this._getHash(props.shader.source);
91
+ return `${shaderHash}`;
165
92
  }
166
93
 
167
94
  /** Calculate a hash based on all the inputs for a render pipeline */
168
- _hashRenderPipeline(props: GetRenderPipelineOptions): string {
169
- const {modules = [], varyings = [], defines = [], inject = [], parameters = []} = props;
170
- const vsHash = this._getHash(props.vs);
171
- const fsHash = props.fs ? this._getHash(props.fs) : 0;
172
-
173
- const moduleHashes = modules.map((m) => this._getHash(typeof m === 'string' ? m : m.name)).sort();
174
- const varyingHashes = varyings.map((v) => this._getHash(v));
175
-
176
- const defineKeys = Object.keys(defines).sort();
177
- const injectKeys = Object.keys(inject).sort();
178
- const defineHashes: number[] = [];
179
- const injectHashes: number[] = [];
180
-
181
- for (const key of defineKeys) {
182
- defineHashes.push(this._getHash(key));
183
- defineHashes.push(this._getHash(defines[key]));
184
- }
185
-
186
- for (const key of injectKeys) {
187
- injectHashes.push(this._getHash(key));
188
- injectHashes.push(this._getHash(inject[key]));
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;
98
+
99
+ // WebGL specific
100
+ // const {varyings = [], bufferMode = {}} = props;
101
+ // const varyingHashes = varyings.map((v) => this._getHash(v));
102
+ const varyingHash = '-'; // `${varyingHashes.join('/')}B${bufferMode}`
103
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
104
+
105
+ switch (this.device.type) {
106
+ // case 'webgl':
107
+ // WebGL is more dynamic
108
+ // return `${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
109
+ default:
110
+ // On WebGPU we need to rebuild the pipeline if topology, parameters or bufferLayout change
111
+ const parameterHash = this._getHash(JSON.stringify(props.parameters));
112
+ // TODO - Can json.stringify() generate different strings for equivalent objects if order of params is different?
113
+ // create a deepHash() to deduplicate?
114
+ return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
189
115
  }
190
-
191
- // TODO - hash parameters!
192
- const parameterHash = JSON.stringify(parameters);
193
-
194
- return `${vsHash}/${fsHash}D${defineHashes.join('/')}M${moduleHashes.join(
195
- '/'
196
- )}I${injectHashes.join('/')}V${varyingHashes.join('/')}H${this.stateHash}B${props.bufferMode}${
197
- props.transpileToGLSL100 ? 'T' : ''
198
- }P${parameterHash}`;
199
116
  }
200
117
 
201
- _getHash(key: string): number {
118
+ private _getHash(key: string): number {
202
119
  if (this._hashes[key] === undefined) {
203
120
  this._hashes[key] = this._hashCounter++;
204
121
  }
205
122
  return this._hashes[key];
206
123
  }
207
-
208
- // Dedupe and combine with default modules
209
- _getModuleList(appModules: ShaderModule[] = []): ShaderModule[] {
210
- const modules = new Array(this._defaultModules.length + appModules.length);
211
- const seen: Record<string, boolean> = {};
212
- let count = 0;
213
-
214
- for (let i = 0, len = this._defaultModules.length; i < len; ++i) {
215
- const module = this._defaultModules[i];
216
- const name = module.name;
217
- modules[count++] = module;
218
- seen[name] = true;
219
- }
220
-
221
- for (let i = 0, len = appModules.length; i < len; ++i) {
222
- const module = appModules[i];
223
- const name = module.name;
224
- if (!seen[name]) {
225
- modules[count++] = module;
226
- seen[name] = true;
227
- }
228
- }
229
-
230
- modules.length = count;
231
-
232
- return modules;
233
- }
234
124
  }