@luma.gl/engine 9.0.0-beta.5 → 9.0.0-beta.7
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.
- package/dist/animation/timeline.d.ts.map +1 -1
- package/dist/animation/timeline.js +3 -3
- package/dist/animation-loop/animation-loop-template.d.ts +1 -1
- package/dist/animation-loop/animation-loop-template.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop-template.js +3 -1
- package/dist/animation-loop/animation-loop.d.ts +2 -2
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +14 -6
- package/dist/animation-loop/animation-props.d.ts +2 -2
- package/dist/animation-loop/animation-props.d.ts.map +1 -1
- package/dist/animation-loop/make-animation-loop.d.ts +2 -2
- package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/make-animation-loop.js +4 -2
- package/dist/computation.d.ts +95 -0
- package/dist/computation.d.ts.map +1 -0
- package/dist/computation.js +248 -0
- package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
- package/dist/debug/copy-texture-to-image.js +5 -2
- package/dist/debug/debug-framebuffer.d.ts.map +1 -1
- package/dist/debug/debug-framebuffer.js +0 -1
- package/dist/debug/pixel-data-utils.d.ts.map +1 -1
- package/dist/debug/pixel-data-utils.js +2 -1
- package/dist/dist.dev.js +713 -329
- package/dist/geometries/cone-geometry.d.ts +1 -1
- package/dist/geometries/cone-geometry.d.ts.map +1 -1
- package/dist/geometries/cone-geometry.js +1 -1
- package/dist/geometries/cube-geometry.d.ts +1 -1
- package/dist/geometries/cube-geometry.d.ts.map +1 -1
- package/dist/geometries/cube-geometry.js +16 -14
- package/dist/geometries/cylinder-geometry.d.ts +1 -1
- package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
- package/dist/geometries/cylinder-geometry.js +1 -1
- package/dist/geometries/ico-sphere-geometry.d.ts +1 -1
- package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/ico-sphere-geometry.js +1 -1
- package/dist/geometries/plane-geometry.d.ts +1 -1
- package/dist/geometries/plane-geometry.d.ts.map +1 -1
- package/dist/geometries/plane-geometry.js +2 -2
- package/dist/geometries/sphere-geometry.d.ts +1 -1
- package/dist/geometries/sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/sphere-geometry.js +1 -1
- package/dist/geometries/truncated-cone-geometry.d.ts +1 -1
- package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
- package/dist/geometries/truncated-cone-geometry.js +1 -1
- package/dist/geometry/geometry-table.d.ts.map +1 -1
- package/dist/geometry/geometry-table.js +3 -0
- package/dist/geometry/geometry.d.ts.map +1 -1
- package/dist/geometry/geometry.js +3 -0
- package/dist/geometry/gpu-geometry.d.ts +1 -1
- package/dist/geometry/gpu-geometry.d.ts.map +1 -1
- package/dist/geometry/gpu-geometry.js +4 -5
- package/dist/index.cjs +661 -291
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +43 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -23
- package/dist/lib/clip-space.d.ts +1 -1
- package/dist/lib/clip-space.d.ts.map +1 -1
- package/dist/lib/clip-space.js +8 -10
- package/dist/lib/pipeline-factory.d.ts +10 -6
- package/dist/lib/pipeline-factory.d.ts.map +1 -1
- package/dist/lib/pipeline-factory.js +47 -22
- package/dist/lib/shader-factory.d.ts +17 -0
- package/dist/lib/shader-factory.d.ts.map +1 -0
- package/dist/lib/shader-factory.js +46 -0
- package/dist/model/model.d.ts +58 -45
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +213 -120
- package/dist/scenegraph/group-node.d.ts +1 -1
- package/dist/scenegraph/group-node.d.ts.map +1 -1
- package/dist/scenegraph/group-node.js +10 -5
- package/dist/scenegraph/model-node.d.ts +3 -3
- package/dist/scenegraph/model-node.d.ts.map +1 -1
- package/dist/scenegraph/model-node.js +2 -2
- package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
- package/dist/shader-inputs.d.ts.map +1 -1
- package/dist/shader-inputs.js +3 -0
- package/dist/transform/buffer-transform.d.ts +1 -1
- package/dist/transform/buffer-transform.d.ts.map +1 -1
- package/dist/transform/buffer-transform.js +7 -6
- package/dist/transform/texture-transform.d.ts +1 -1
- package/dist/transform/texture-transform.d.ts.map +1 -1
- package/dist/transform/texture-transform.js +10 -8
- package/dist.min.js +2 -2
- package/package.json +2 -2
- package/src/animation/timeline.ts +20 -20
- package/src/animation-loop/animation-loop-template.ts +10 -8
- package/src/animation-loop/animation-loop.ts +20 -10
- package/src/animation-loop/animation-props.ts +1 -1
- package/src/animation-loop/make-animation-loop.ts +17 -8
- package/src/computation.ts +346 -0
- package/src/debug/copy-texture-to-image.ts +8 -6
- package/src/debug/debug-framebuffer.ts +16 -3
- package/src/debug/debug-shader-layout.ts +1 -1
- package/src/debug/pixel-data-utils.ts +3 -6
- package/src/geometries/cube-geometry.ts +17 -13
- package/src/geometries/ico-sphere-geometry.ts +1 -1
- package/src/geometries/plane-geometry.ts +1 -1
- package/src/geometries/sphere-geometry.ts +1 -1
- package/src/geometries/truncated-cone-geometry.ts +2 -1
- package/src/geometry/geometry-table.ts +9 -6
- package/src/geometry/geometry-utils.ts +1 -1
- package/src/geometry/geometry.ts +9 -6
- package/src/geometry/gpu-geometry.ts +18 -11
- package/src/index.ts +3 -0
- package/src/lib/clip-space.ts +14 -18
- package/src/lib/pipeline-factory.ts +62 -28
- package/src/lib/shader-factory.ts +57 -0
- package/src/model/model.ts +249 -146
- package/src/scenegraph/group-node.ts +14 -10
- package/src/scenegraph/model-node.ts +2 -2
- package/src/scenegraph/scenegraph-node.ts +2 -2
- package/src/shader-inputs.ts +19 -12
- package/src/transform/buffer-transform.ts +15 -7
- package/src/transform/texture-transform.ts +14 -13
|
@@ -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
|
|
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
|
+
};
|
package/src/geometry/geometry.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
// luma.gl
|
|
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
|
|
52
|
-
this.attributes
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
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':
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
case '
|
|
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';
|
|
@@ -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';
|
package/src/lib/clip-space.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
// ClipSpace
|
|
3
2
|
import {Device, glsl} from '@luma.gl/core';
|
|
4
3
|
import {Model, ModelProps} from '../model/model';
|
|
@@ -30,24 +29,21 @@ const POSITIONS = [-1, -1, 1, -1, -1, 1, 1, 1];
|
|
|
30
29
|
*/
|
|
31
30
|
export class ClipSpace extends Model {
|
|
32
31
|
constructor(device: Device, opts: Omit<ModelProps, 'vs' | 'vertexCount' | 'geometry'>) {
|
|
33
|
-
const TEX_COORDS = POSITIONS.map(
|
|
32
|
+
const TEX_COORDS = POSITIONS.map(coord => (coord === -1 ? 0 : coord));
|
|
34
33
|
|
|
35
|
-
super(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
super(device, {
|
|
35
|
+
...opts,
|
|
36
|
+
vs: CLIPSPACE_VERTEX_SHADER,
|
|
37
|
+
vertexCount: 4,
|
|
38
|
+
geometry: new Geometry({
|
|
39
|
+
topology: 'triangle-strip',
|
|
40
40
|
vertexCount: 4,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
})
|
|
50
|
-
}
|
|
51
|
-
);
|
|
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
|
+
});
|
|
52
48
|
}
|
|
53
49
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
// luma.gl
|
|
2
|
-
|
|
3
|
-
|
|
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';
|
|
4
7
|
|
|
5
8
|
export type PipelineFactoryProps = RenderPipelineProps;
|
|
6
9
|
|
|
@@ -14,9 +17,16 @@ export class PipelineFactory {
|
|
|
14
17
|
|
|
15
18
|
private _hashCounter: number = 0;
|
|
16
19
|
private readonly _hashes: Record<string, number> = {};
|
|
17
|
-
private readonly
|
|
18
|
-
|
|
19
|
-
|
|
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 */
|
|
20
30
|
static getDefaultPipelineFactory(device: Device): PipelineFactory {
|
|
21
31
|
device._lumaData.defaultPipelineFactory =
|
|
22
32
|
device._lumaData.defaultPipelineFactory || new PipelineFactory(device);
|
|
@@ -27,38 +37,62 @@ export class PipelineFactory {
|
|
|
27
37
|
this.device = device;
|
|
28
38
|
}
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const hash = this._hashRenderPipeline({...props});
|
|
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};
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
const pipeline = this.device.createRenderPipeline({...props});
|
|
44
|
+
const hash = this._hashRenderPipeline(allProps);
|
|
37
45
|
|
|
46
|
+
if (!this._renderPipelineCache[hash]) {
|
|
47
|
+
const pipeline = this.device.createRenderPipeline({
|
|
48
|
+
...allProps,
|
|
49
|
+
id: allProps.id ? `${allProps.id}-cached` : undefined
|
|
50
|
+
});
|
|
38
51
|
pipeline.hash = hash;
|
|
39
|
-
this.
|
|
40
|
-
this._useCounts[hash] = 0;
|
|
52
|
+
this._renderPipelineCache[hash] = {pipeline, useCount: 0};
|
|
41
53
|
}
|
|
42
54
|
|
|
43
|
-
this.
|
|
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);
|
|
44
63
|
|
|
45
|
-
|
|
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
|
+
}
|
|
72
|
+
|
|
73
|
+
this._computePipelineCache[hash].useCount++;
|
|
74
|
+
return this._computePipelineCache[hash].pipeline;
|
|
46
75
|
}
|
|
47
76
|
|
|
48
|
-
release(pipeline: RenderPipeline): void {
|
|
77
|
+
release(pipeline: RenderPipeline | ComputePipeline): void {
|
|
49
78
|
const hash = pipeline.hash;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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];
|
|
55
85
|
}
|
|
56
86
|
}
|
|
57
87
|
|
|
58
88
|
// PRIVATE
|
|
89
|
+
private _hashComputePipeline(props: ComputePipelineProps): string {
|
|
90
|
+
const shaderHash = this._getHash(props.shader.source);
|
|
91
|
+
return `${shaderHash}`;
|
|
92
|
+
}
|
|
59
93
|
|
|
60
94
|
/** Calculate a hash based on all the inputs for a render pipeline */
|
|
61
|
-
private _hashRenderPipeline(props:
|
|
95
|
+
private _hashRenderPipeline(props: RenderPipelineProps): string {
|
|
62
96
|
const vsHash = this._getHash(props.vs.source);
|
|
63
97
|
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
64
98
|
|
|
@@ -68,16 +102,16 @@ export class PipelineFactory {
|
|
|
68
102
|
const varyingHash = '-'; // `${varyingHashes.join('/')}B${bufferMode}`
|
|
69
103
|
const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
|
|
70
104
|
|
|
71
|
-
switch (this.device.
|
|
72
|
-
case '
|
|
105
|
+
switch (this.device.type) {
|
|
106
|
+
// case 'webgl':
|
|
107
|
+
// WebGL is more dynamic
|
|
108
|
+
// return `${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
|
|
109
|
+
default:
|
|
73
110
|
// On WebGPU we need to rebuild the pipeline if topology, parameters or bufferLayout change
|
|
74
111
|
const parameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
75
112
|
// TODO - Can json.stringify() generate different strings for equivalent objects if order of params is different?
|
|
76
113
|
// create a deepHash() to deduplicate?
|
|
77
114
|
return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
|
|
78
|
-
default:
|
|
79
|
-
// WebGL is more dynamic
|
|
80
|
-
return `${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
|
|
81
115
|
}
|
|
82
116
|
}
|
|
83
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
|
+
}
|