@lightningjs/renderer 0.3.3 → 0.3.4
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/src/core/CoreTextureManager.d.ts +4 -3
- package/dist/src/core/CoreTextureManager.js +7 -4
- package/dist/src/core/CoreTextureManager.js.map +1 -1
- package/dist/src/core/renderers/webgl/shaders/DynamicShader.d.ts +36 -1
- package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +2 -2
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +6 -1
- package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +1 -1
- package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
- package/dist/src/core/textures/SubTexture.d.ts +2 -2
- package/dist/src/main-api/INode.d.ts +5 -5
- package/dist/src/main-api/RendererMain.d.ts +88 -8
- package/dist/src/main-api/RendererMain.js +22 -6
- package/dist/src/main-api/RendererMain.js.map +1 -1
- package/dist/src/render-drivers/main/MainOnlyNode.d.ts +7 -7
- package/dist/src/render-drivers/main/MainOnlyNode.js +8 -1
- package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
- package/dist/src/render-drivers/threadx/ThreadXMainNode.d.ts +8 -7
- package/dist/src/render-drivers/threadx/ThreadXMainNode.js +11 -1
- package/dist/src/render-drivers/threadx/ThreadXMainNode.js.map +1 -1
- package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +0 -1
- package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/CoreTextureManager.ts +7 -6
- package/src/core/renderers/webgl/shaders/DynamicShader.ts +42 -2
- package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +9 -3
- package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +6 -4
- package/src/core/textures/SubTexture.ts +2 -2
- package/src/main-api/INode.ts +5 -5
- package/src/main-api/RendererMain.ts +125 -23
- package/src/main-api/texture-usage-trackers/FinalizationRegistryTextureUsageTracker.ts +45 -0
- package/src/main-api/texture-usage-trackers/ManualCountTextureUsageTracker.ts +154 -0
- package/src/main-api/texture-usage-trackers/TextureUsageTracker.ts +54 -0
- package/src/render-drivers/main/MainOnlyNode.ts +16 -9
- package/src/render-drivers/threadx/ThreadXMainNode.ts +20 -9
- package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +5 -9
|
@@ -38,6 +38,44 @@ import { GlitchEffect } from './effects/GlitchEffect.js';
|
|
|
38
38
|
import { FadeOutEffect } from './effects/FadeOutEffect.js';
|
|
39
39
|
import { RadialGradientEffect } from './effects/RadialGradientEffect.js';
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Allows the `keyof EffectMap` to be mapped over and form an discriminated
|
|
43
|
+
* union of all the EffectDescs structures individually.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* When used like the following:
|
|
47
|
+
* ```
|
|
48
|
+
* MapEffectDescs<keyof EffectMap>[]
|
|
49
|
+
* ```
|
|
50
|
+
* The resultant type will be a discriminated union like so:
|
|
51
|
+
* ```
|
|
52
|
+
* (
|
|
53
|
+
* {
|
|
54
|
+
* type: 'radius',
|
|
55
|
+
* props?: {
|
|
56
|
+
* radius?: number | number[];
|
|
57
|
+
* }
|
|
58
|
+
* } |
|
|
59
|
+
* {
|
|
60
|
+
* type: 'border',
|
|
61
|
+
* props?: {
|
|
62
|
+
* width?: number;
|
|
63
|
+
* color?: number;
|
|
64
|
+
* }
|
|
65
|
+
* } |
|
|
66
|
+
* // ...
|
|
67
|
+
* )[]
|
|
68
|
+
* ```
|
|
69
|
+
* Which means TypeScript will now base its type checking on the `type` field
|
|
70
|
+
* and will know exactly what the `props` field should be based on the `type`
|
|
71
|
+
* field.
|
|
72
|
+
*/
|
|
73
|
+
type MapEffectDescs<T extends keyof EffectMap> = T extends keyof EffectMap
|
|
74
|
+
? SpecificEffectDesc<T>
|
|
75
|
+
: never;
|
|
76
|
+
|
|
77
|
+
type EffectDesc = MapEffectDescs<keyof EffectMap>;
|
|
78
|
+
|
|
41
79
|
export interface DynamicShaderProps
|
|
42
80
|
extends DimensionsShaderProp,
|
|
43
81
|
AlphaShaderProp {
|
|
@@ -72,7 +110,9 @@ const Effects = {
|
|
|
72
110
|
glitch: GlitchEffect,
|
|
73
111
|
};
|
|
74
112
|
|
|
75
|
-
export interface
|
|
113
|
+
export interface SpecificEffectDesc<
|
|
114
|
+
FxType extends keyof EffectMap = keyof EffectMap,
|
|
115
|
+
> {
|
|
76
116
|
type: FxType;
|
|
77
117
|
props?: ExtractProps<EffectMap[FxType]>;
|
|
78
118
|
}
|
|
@@ -325,7 +365,7 @@ export class DynamicShader extends WebGlCoreShader {
|
|
|
325
365
|
effects: (props.effects ?? []).map((effect) => ({
|
|
326
366
|
type: effect.type,
|
|
327
367
|
props: Effects[effect.type].resolveDefaults(effect.props || {}),
|
|
328
|
-
})),
|
|
368
|
+
})) as MapEffectDescs<keyof EffectMap>[],
|
|
329
369
|
$dimensions: {
|
|
330
370
|
width: 0,
|
|
331
371
|
height: 0,
|
|
@@ -85,12 +85,18 @@ export interface CanvasTextRendererState extends TextRendererState {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
export class CanvasTextRenderer extends TextRenderer<CanvasTextRendererState> {
|
|
88
|
-
protected canvas: OffscreenCanvas;
|
|
89
|
-
protected context:
|
|
88
|
+
protected canvas: OffscreenCanvas | HTMLCanvasElement;
|
|
89
|
+
protected context:
|
|
90
|
+
| OffscreenCanvasRenderingContext2D
|
|
91
|
+
| CanvasRenderingContext2D;
|
|
90
92
|
|
|
91
93
|
constructor(stage: Stage) {
|
|
92
94
|
super(stage);
|
|
93
|
-
|
|
95
|
+
if (typeof OffscreenCanvas !== 'undefined') {
|
|
96
|
+
this.canvas = new OffscreenCanvas(0, 0);
|
|
97
|
+
} else {
|
|
98
|
+
this.canvas = document.createElement('canvas');
|
|
99
|
+
}
|
|
94
100
|
const context = this.canvas.getContext('2d');
|
|
95
101
|
assertTruthy(context);
|
|
96
102
|
this.context = context;
|
|
@@ -126,14 +126,16 @@ export interface RenderInfo {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
export class LightningTextTextureRenderer {
|
|
129
|
-
private _canvas: OffscreenCanvas;
|
|
130
|
-
private _context:
|
|
129
|
+
private _canvas: OffscreenCanvas | HTMLCanvasElement;
|
|
130
|
+
private _context:
|
|
131
|
+
| OffscreenCanvasRenderingContext2D
|
|
132
|
+
| CanvasRenderingContext2D;
|
|
131
133
|
private _settings: Settings;
|
|
132
134
|
private renderInfo: RenderInfo | undefined;
|
|
133
135
|
|
|
134
136
|
constructor(
|
|
135
|
-
canvas: OffscreenCanvas,
|
|
136
|
-
context: OffscreenCanvasRenderingContext2D,
|
|
137
|
+
canvas: OffscreenCanvas | HTMLCanvasElement,
|
|
138
|
+
context: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,
|
|
137
139
|
) {
|
|
138
140
|
this._canvas = canvas;
|
|
139
141
|
this._context = context;
|
|
@@ -21,7 +21,7 @@ import type {
|
|
|
21
21
|
TextureFailedEventHandler,
|
|
22
22
|
TextureLoadedEventHandler,
|
|
23
23
|
} from '../../common/CommonTypes.js';
|
|
24
|
-
import type {
|
|
24
|
+
import type { TextureRef } from '../../main-api/RendererMain.js';
|
|
25
25
|
import type { CoreTextureManager } from '../CoreTextureManager.js';
|
|
26
26
|
import { Texture } from './Texture.js';
|
|
27
27
|
|
|
@@ -32,7 +32,7 @@ export interface SubTextureProps {
|
|
|
32
32
|
/**
|
|
33
33
|
* The texture that this sub-texture is a sub-region of.
|
|
34
34
|
*/
|
|
35
|
-
texture:
|
|
35
|
+
texture: TextureRef;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* The x pixel position of the top-left of the sub-texture within the parent
|
package/src/main-api/INode.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import type { IEventEmitter } from '@lightningjs/threadx';
|
|
21
21
|
import type { IAnimationController } from '../common/IAnimationController.js';
|
|
22
|
-
import type {
|
|
22
|
+
import type { ShaderRef, TextureRef } from './RendererMain.js';
|
|
23
23
|
import type {
|
|
24
24
|
TextRendererMap,
|
|
25
25
|
TrProps,
|
|
@@ -206,7 +206,7 @@ export interface INodeWritableProps {
|
|
|
206
206
|
* and TBD properties.
|
|
207
207
|
*
|
|
208
208
|
* To create a Texture in order to set it on this property, call
|
|
209
|
-
* {@link RendererMain.
|
|
209
|
+
* {@link RendererMain.createTexture}.
|
|
210
210
|
*
|
|
211
211
|
* If the {@link src} is set on a Node, the Node will use the
|
|
212
212
|
* {@link ImageTexture} by default and the Node will simply load the image at
|
|
@@ -215,7 +215,7 @@ export interface INodeWritableProps {
|
|
|
215
215
|
* Note: If this is a Text Node, the Texture will be managed by the Node's
|
|
216
216
|
* {@link TextRenderer} and should not be set explicitly.
|
|
217
217
|
*/
|
|
218
|
-
texture:
|
|
218
|
+
texture: TextureRef | null;
|
|
219
219
|
/**
|
|
220
220
|
* The Node's shader
|
|
221
221
|
*
|
|
@@ -225,12 +225,12 @@ export interface INodeWritableProps {
|
|
|
225
225
|
* or {@link color}(s) within the Node without any special effects.
|
|
226
226
|
*
|
|
227
227
|
* To create a Shader in order to set it on this property, call
|
|
228
|
-
* {@link RendererMain.
|
|
228
|
+
* {@link RendererMain.createShader}.
|
|
229
229
|
*
|
|
230
230
|
* Note: If this is a Text Node, the Shader will be managed by the Node's
|
|
231
231
|
* {@link TextRenderer} and should not be set explicitly.
|
|
232
232
|
*/
|
|
233
|
-
shader:
|
|
233
|
+
shader: ShaderRef | null;
|
|
234
234
|
/**
|
|
235
235
|
* Image URL
|
|
236
236
|
*
|
|
@@ -31,29 +31,80 @@ import type {
|
|
|
31
31
|
ITextNodeWritableProps,
|
|
32
32
|
} from './INode.js';
|
|
33
33
|
import type { IRenderDriver } from './IRenderDriver.js';
|
|
34
|
+
import {
|
|
35
|
+
ManualCountTextureUsageTracker,
|
|
36
|
+
type ManualCountTextureUsageTrackerOptions,
|
|
37
|
+
} from './texture-usage-trackers/ManualCountTextureUsageTracker.js';
|
|
38
|
+
import { FinalizationRegistryTextureUsageTracker } from './texture-usage-trackers/FinalizationRegistryTextureUsageTracker.js';
|
|
39
|
+
import type { TextureUsageTracker } from './texture-usage-trackers/TextureUsageTracker.js';
|
|
34
40
|
|
|
35
41
|
/**
|
|
36
|
-
*
|
|
42
|
+
* An immutable reference to a specific Texture type
|
|
37
43
|
*
|
|
38
44
|
* @remarks
|
|
39
|
-
*
|
|
40
|
-
* method. The structure is immutable and should not be modified once created.
|
|
45
|
+
* See {@link TextureRef} for more details.
|
|
41
46
|
*/
|
|
42
|
-
export interface
|
|
43
|
-
TxType extends keyof TextureMap = keyof TextureMap,
|
|
44
|
-
> {
|
|
47
|
+
export interface SpecificTextureRef<TxType extends keyof TextureMap> {
|
|
45
48
|
readonly descType: 'texture';
|
|
46
49
|
readonly txType: TxType;
|
|
47
50
|
readonly props: ExtractProps<TextureMap[TxType]>;
|
|
48
51
|
readonly options?: Readonly<TextureOptions>;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
|
|
54
|
+
type MapTextureRefs<TxType extends keyof TextureMap> =
|
|
55
|
+
TxType extends keyof TextureMap ? SpecificTextureRef<TxType> : never;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* An immutable reference to a Texture
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* This structure should only be created by the RendererMain's `createTexture`
|
|
62
|
+
* method. The structure is immutable and should not be modified once created.
|
|
63
|
+
*
|
|
64
|
+
* A `TextureRef` exists in the Main API Space and is used to point to an actual
|
|
65
|
+
* `Texture` instance in the Core API Space. The `TextureRef` is used to
|
|
66
|
+
* communicate with the Core API Space to create, load, and destroy the
|
|
67
|
+
* `Texture` instance.
|
|
68
|
+
*
|
|
69
|
+
* This type is technically a discriminated union of all possible texture types.
|
|
70
|
+
* If you'd like to represent a specific texture type, you can use the
|
|
71
|
+
* `SpecificTextureRef` generic type.
|
|
72
|
+
*/
|
|
73
|
+
export type TextureRef = MapTextureRefs<keyof TextureMap>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* An immutable reference to a specific Shader type
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* See {@link ShaderRef} for more details.
|
|
80
|
+
*/
|
|
81
|
+
export interface SpecificShaderRef<ShType extends keyof ShaderMap> {
|
|
52
82
|
readonly descType: 'shader';
|
|
53
83
|
readonly shType: ShType;
|
|
54
84
|
readonly props: ExtractProps<ShaderMap[ShType]>;
|
|
55
85
|
}
|
|
56
86
|
|
|
87
|
+
type MapShaderRefs<ShType extends keyof ShaderMap> =
|
|
88
|
+
ShType extends keyof ShaderMap ? SpecificShaderRef<ShType> : never;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* An immutable reference to a Shader
|
|
92
|
+
*
|
|
93
|
+
* @remarks
|
|
94
|
+
* This structure should only be created by the RendererMain's `createShader`
|
|
95
|
+
* method. The structure is immutable and should not be modified once created.
|
|
96
|
+
*
|
|
97
|
+
* A `ShaderRef` exists in the Main API Space and is used to point to an actual
|
|
98
|
+
* `Shader` instance in the Core API Space. The `ShaderRef` is used to
|
|
99
|
+
* communicate with the Core API Space to create, load, and destroy the
|
|
100
|
+
* `Shader` instance.
|
|
101
|
+
*
|
|
102
|
+
* This type is technically a discriminated union of all possible shader types.
|
|
103
|
+
* If you'd like to represent a specific shader type, you can use the
|
|
104
|
+
* `SpecificShaderRef` generic type.
|
|
105
|
+
*/
|
|
106
|
+
export type ShaderRef = MapShaderRefs<keyof ShaderMap>;
|
|
107
|
+
|
|
57
108
|
/**
|
|
58
109
|
* Configuration settings for {@link RendererMain}
|
|
59
110
|
*/
|
|
@@ -115,8 +166,40 @@ export interface RendererMainSettings {
|
|
|
115
166
|
|
|
116
167
|
/**
|
|
117
168
|
* Path to a custom core module to use
|
|
169
|
+
*
|
|
170
|
+
* @defaultValue `null`
|
|
118
171
|
*/
|
|
119
172
|
coreExtensionModule?: string | null;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Enable experimental FinalizationRegistry-based texture usage tracking
|
|
176
|
+
* for texture garbage collection
|
|
177
|
+
*
|
|
178
|
+
* @remarks
|
|
179
|
+
* By default, the Renderer uses a manual reference counting system to track
|
|
180
|
+
* texture usage. Textures are eventually released from the Core Texture
|
|
181
|
+
* Manager's Usage Cache when they are no longer referenced by any Nodes (or
|
|
182
|
+
* SubTextures that are referenced by nodes). This works well enough, but has
|
|
183
|
+
* the consequence of textures being removed from Usage Cache even if their
|
|
184
|
+
* references are still alive in memory. This can require a texture to be
|
|
185
|
+
* reloaded from the source when it is used again after being removed from
|
|
186
|
+
* cache.
|
|
187
|
+
*
|
|
188
|
+
* This is an experimental feature that uses a FinalizationRegistry to track
|
|
189
|
+
* texture usage. This causes textures to be removed from the Usage Cache only
|
|
190
|
+
* when their references are no longer alive in memory. Meaning a loaded texture
|
|
191
|
+
* will remain in the Usage Cache until it's reference is garbage collected.
|
|
192
|
+
*
|
|
193
|
+
* This feature is not enabled by default because browser support for the
|
|
194
|
+
* FinalizationRegistry is limited. It should NOT be enabled in production apps
|
|
195
|
+
* as this behavior is not guaranteed to be supported in the future. Developer
|
|
196
|
+
* feedback on this feature, however, is welcome.
|
|
197
|
+
*
|
|
198
|
+
* @defaultValue `false`
|
|
199
|
+
*/
|
|
200
|
+
experimental_FinalizationRegistryTextureUsageTracker?: boolean;
|
|
201
|
+
|
|
202
|
+
textureCleanupOptions?: ManualCountTextureUsageTrackerOptions;
|
|
120
203
|
}
|
|
121
204
|
|
|
122
205
|
/**
|
|
@@ -151,11 +234,13 @@ export class RendererMain {
|
|
|
151
234
|
private nodes: Map<number, INode> = new Map();
|
|
152
235
|
private nextTextureId = 1;
|
|
153
236
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Texture Usage Tracker for Usage Based Texture Garbage Collection
|
|
239
|
+
*
|
|
240
|
+
* @remarks
|
|
241
|
+
* For internal use only. DO NOT ACCESS.
|
|
242
|
+
*/
|
|
243
|
+
public textureTracker: TextureUsageTracker;
|
|
159
244
|
|
|
160
245
|
/**
|
|
161
246
|
* Constructs a new Renderer instance
|
|
@@ -177,6 +262,9 @@ export class RendererMain {
|
|
|
177
262
|
settings.devicePhysicalPixelRatio || window.devicePixelRatio,
|
|
178
263
|
clearColor: settings.clearColor ?? 0x00000000,
|
|
179
264
|
coreExtensionModule: settings.coreExtensionModule || null,
|
|
265
|
+
experimental_FinalizationRegistryTextureUsageTracker:
|
|
266
|
+
settings.experimental_FinalizationRegistryTextureUsageTracker ?? false,
|
|
267
|
+
textureCleanupOptions: settings.textureCleanupOptions || {},
|
|
180
268
|
};
|
|
181
269
|
this.settings = resolvedSettings;
|
|
182
270
|
|
|
@@ -187,6 +275,20 @@ export class RendererMain {
|
|
|
187
275
|
devicePhysicalPixelRatio,
|
|
188
276
|
} = resolvedSettings;
|
|
189
277
|
|
|
278
|
+
const releaseCallback = (textureId: number) => {
|
|
279
|
+
this.driver.releaseTexture(textureId);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const useFinalizationRegistryTracker =
|
|
283
|
+
resolvedSettings.experimental_FinalizationRegistryTextureUsageTracker &&
|
|
284
|
+
typeof FinalizationRegistry === 'function';
|
|
285
|
+
this.textureTracker = useFinalizationRegistryTracker
|
|
286
|
+
? new FinalizationRegistryTextureUsageTracker(releaseCallback)
|
|
287
|
+
: new ManualCountTextureUsageTracker(
|
|
288
|
+
releaseCallback,
|
|
289
|
+
this.settings.textureCleanupOptions,
|
|
290
|
+
);
|
|
291
|
+
|
|
190
292
|
const deviceLogicalWidth = appWidth * deviceLogicalPixelRatio;
|
|
191
293
|
const deviceLogicalHeight = appHeight * deviceLogicalPixelRatio;
|
|
192
294
|
|
|
@@ -373,13 +475,13 @@ export class RendererMain {
|
|
|
373
475
|
* @param options
|
|
374
476
|
* @returns
|
|
375
477
|
*/
|
|
376
|
-
|
|
377
|
-
textureType:
|
|
378
|
-
props:
|
|
478
|
+
createTexture<TxType extends keyof TextureMap>(
|
|
479
|
+
textureType: TxType,
|
|
480
|
+
props: SpecificTextureRef<TxType>['props'],
|
|
379
481
|
options?: TextureOptions,
|
|
380
|
-
):
|
|
482
|
+
): SpecificTextureRef<TxType> {
|
|
381
483
|
const id = this.nextTextureId++;
|
|
382
|
-
const desc
|
|
484
|
+
const desc = {
|
|
383
485
|
descType: 'texture',
|
|
384
486
|
txType: textureType,
|
|
385
487
|
props,
|
|
@@ -389,8 +491,8 @@ export class RendererMain {
|
|
|
389
491
|
// ID Texture Map cache.
|
|
390
492
|
id,
|
|
391
493
|
},
|
|
392
|
-
}
|
|
393
|
-
this.
|
|
494
|
+
} satisfies SpecificTextureRef<TxType>;
|
|
495
|
+
this.textureTracker.registerTexture(desc as TextureRef);
|
|
394
496
|
return desc;
|
|
395
497
|
}
|
|
396
498
|
|
|
@@ -407,14 +509,14 @@ export class RendererMain {
|
|
|
407
509
|
* @param props
|
|
408
510
|
* @returns
|
|
409
511
|
*/
|
|
410
|
-
|
|
512
|
+
createShader<ShType extends keyof ShaderMap>(
|
|
411
513
|
shaderType: ShType,
|
|
412
|
-
props?:
|
|
413
|
-
):
|
|
514
|
+
props?: SpecificShaderRef<ShType>['props'],
|
|
515
|
+
): SpecificShaderRef<ShType> {
|
|
414
516
|
return {
|
|
415
517
|
descType: 'shader',
|
|
416
518
|
shType: shaderType,
|
|
417
|
-
props: props as
|
|
519
|
+
props: props as SpecificShaderRef<ShType>['props'],
|
|
418
520
|
};
|
|
419
521
|
}
|
|
420
522
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* If not stated otherwise in this file or this component's LICENSE file the
|
|
3
|
+
* following copyright and licenses apply:
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2023 Comcast Cable Communications Management, LLC.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the License);
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { assertTruthy } from '../../utils.js';
|
|
21
|
+
import type { TextureRef } from '../RendererMain.js';
|
|
22
|
+
import { TextureUsageTracker } from './TextureUsageTracker.js';
|
|
23
|
+
|
|
24
|
+
export class FinalizationRegistryTextureUsageTracker extends TextureUsageTracker {
|
|
25
|
+
private registry: FinalizationRegistry<number>;
|
|
26
|
+
|
|
27
|
+
constructor(releaseCallback: (textureDescId: number) => void) {
|
|
28
|
+
super(releaseCallback);
|
|
29
|
+
this.registry = new FinalizationRegistry(releaseCallback);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override registerTexture(texture: TextureRef): void {
|
|
33
|
+
assertTruthy(
|
|
34
|
+
texture.options?.id,
|
|
35
|
+
'Texture must have an ID to be registered',
|
|
36
|
+
);
|
|
37
|
+
this.registry.register(texture, texture.options?.id);
|
|
38
|
+
}
|
|
39
|
+
override incrementTextureRefCount(): void {
|
|
40
|
+
// No-op for FinalizationRegistry
|
|
41
|
+
}
|
|
42
|
+
override decrementTextureRefCount(): void {
|
|
43
|
+
// No-op for FinalizationRegistry
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* If not stated otherwise in this file or this component's LICENSE file the
|
|
3
|
+
* following copyright and licenses apply:
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2023 Comcast Cable Communications Management, LLC.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the License);
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { assertTruthy } from '../../utils.js';
|
|
21
|
+
import type { TextureRef } from '../RendererMain.js';
|
|
22
|
+
import { TextureUsageTracker } from './TextureUsageTracker.js';
|
|
23
|
+
|
|
24
|
+
interface TextureRefInfo {
|
|
25
|
+
/**
|
|
26
|
+
* Texture Reference ID
|
|
27
|
+
*/
|
|
28
|
+
id: number;
|
|
29
|
+
/**
|
|
30
|
+
* The number of references to this texture that are currently assigned to
|
|
31
|
+
* Nodes.
|
|
32
|
+
*/
|
|
33
|
+
nodeRefCount: number;
|
|
34
|
+
/**
|
|
35
|
+
* The last time the texture reference count was updated.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* This is used to determine when a texture is no longer referenced by any
|
|
39
|
+
* Nodes and can be removed from the GPU.
|
|
40
|
+
*/
|
|
41
|
+
lastUpdate: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ManualCountTextureUsageTrackerOptions {
|
|
45
|
+
/**
|
|
46
|
+
* The interval at which to check if textures that are no longer referenced
|
|
47
|
+
* by any Nodes can be released from the Core Space Texture Usage Cache.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* Only valid when the {@link ManualCountTextureUsageTracker} is used.
|
|
51
|
+
*
|
|
52
|
+
* @defaultValue 10000 (10 seconds)
|
|
53
|
+
*/
|
|
54
|
+
textureCleanupIntervalMs?: number;
|
|
55
|
+
/**
|
|
56
|
+
* The age at which a texture is considered to be no longer referenced by any
|
|
57
|
+
* Nodes and can be released from the Core Space Texture Usage Cache.
|
|
58
|
+
*
|
|
59
|
+
* @remarks
|
|
60
|
+
* Only valid when the {@link ManualCountTextureUsageTracker} is used.
|
|
61
|
+
*
|
|
62
|
+
* @defaultValue 60000 (1 minute)
|
|
63
|
+
*/
|
|
64
|
+
textureCleanupAgeThreadholdMs?: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Usage-based Texture Garbage Collection Registry
|
|
69
|
+
*/
|
|
70
|
+
export class ManualCountTextureUsageTracker extends TextureUsageTracker {
|
|
71
|
+
textureMap: Map<number, TextureRefInfo> = new Map();
|
|
72
|
+
zeroReferenceTextureSet: Set<TextureRefInfo> = new Set();
|
|
73
|
+
options: Required<ManualCountTextureUsageTrackerOptions>;
|
|
74
|
+
|
|
75
|
+
constructor(
|
|
76
|
+
releaseCallback: (textureDescId: number) => void,
|
|
77
|
+
options: ManualCountTextureUsageTrackerOptions,
|
|
78
|
+
) {
|
|
79
|
+
super(releaseCallback);
|
|
80
|
+
this.options = {
|
|
81
|
+
textureCleanupIntervalMs: options.textureCleanupIntervalMs ?? 10000,
|
|
82
|
+
textureCleanupAgeThreadholdMs:
|
|
83
|
+
options.textureCleanupAgeThreadholdMs ?? 60000,
|
|
84
|
+
};
|
|
85
|
+
// Periodically check for textures that are no longer referenced by any
|
|
86
|
+
// Nodes and notify RendererMain to release them.
|
|
87
|
+
setInterval(() => {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const thresholdMs = this.options.textureCleanupAgeThreadholdMs;
|
|
90
|
+
for (const textureRefInfo of this.zeroReferenceTextureSet) {
|
|
91
|
+
if (now - textureRefInfo.lastUpdate > thresholdMs) {
|
|
92
|
+
this.releaseCallback(textureRefInfo.id);
|
|
93
|
+
this.textureMap.delete(textureRefInfo.id);
|
|
94
|
+
this.zeroReferenceTextureSet.delete(textureRefInfo);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}, this.options.textureCleanupIntervalMs);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
registerTexture(texture: TextureRef) {
|
|
101
|
+
const textureId = texture.options?.id;
|
|
102
|
+
assertTruthy(textureId, 'Texture must have an id to be registered');
|
|
103
|
+
if (!this.textureMap.has(textureId)) {
|
|
104
|
+
const textureRefInfo: TextureRefInfo = {
|
|
105
|
+
id: textureId,
|
|
106
|
+
nodeRefCount: 0,
|
|
107
|
+
lastUpdate: Date.now(),
|
|
108
|
+
};
|
|
109
|
+
this.textureMap.set(textureId, textureRefInfo);
|
|
110
|
+
this.zeroReferenceTextureSet.add(textureRefInfo);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
incrementTextureRefCount(texture: TextureRef) {
|
|
115
|
+
const textureId = texture.options?.id;
|
|
116
|
+
assertTruthy(textureId, 'Texture must have an id to be registered');
|
|
117
|
+
let textureRefInfo = this.textureMap.get(textureId);
|
|
118
|
+
if (!textureRefInfo) {
|
|
119
|
+
// Texture has not been registered yet, so register it now.
|
|
120
|
+
// This may happen if the TextureRef was cleaned up from the registry
|
|
121
|
+
// but was still alive in memory and eventually re-used.
|
|
122
|
+
this.registerTexture(texture);
|
|
123
|
+
textureRefInfo = this.textureMap.get(textureId);
|
|
124
|
+
}
|
|
125
|
+
assertTruthy(textureRefInfo, 'Texture must have been registered');
|
|
126
|
+
if (texture.txType === 'SubTexture') {
|
|
127
|
+
// If this is a SubTexture, then increment the reference count of the
|
|
128
|
+
// parent texture as well.
|
|
129
|
+
this.incrementTextureRefCount(texture.props.texture);
|
|
130
|
+
}
|
|
131
|
+
textureRefInfo.nodeRefCount++;
|
|
132
|
+
textureRefInfo.lastUpdate = Date.now();
|
|
133
|
+
if (this.zeroReferenceTextureSet.has(textureRefInfo)) {
|
|
134
|
+
this.zeroReferenceTextureSet.delete(textureRefInfo);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
decrementTextureRefCount(texture: TextureRef) {
|
|
139
|
+
const textureId = texture.options?.id;
|
|
140
|
+
assertTruthy(textureId, 'Texture must have an id to be registered');
|
|
141
|
+
const textureRefInfo = this.textureMap.get(textureId);
|
|
142
|
+
assertTruthy(textureRefInfo, 'Texture must have been registered');
|
|
143
|
+
textureRefInfo.nodeRefCount--;
|
|
144
|
+
textureRefInfo.lastUpdate = Date.now();
|
|
145
|
+
if (textureRefInfo.nodeRefCount === 0) {
|
|
146
|
+
this.zeroReferenceTextureSet.add(textureRefInfo);
|
|
147
|
+
}
|
|
148
|
+
if (texture.txType === 'SubTexture') {
|
|
149
|
+
// If this is a SubTexture, then decrement the reference count of the
|
|
150
|
+
// parent texture as well.
|
|
151
|
+
this.decrementTextureRefCount(texture.props.texture);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* If not stated otherwise in this file or this component's LICENSE file the
|
|
3
|
+
* following copyright and licenses apply:
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2023 Comcast Cable Communications Management, LLC.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the License);
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { TextureRef } from '../RendererMain.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Texture Usage Tracker for Usage Based Texture Garbage Collection
|
|
24
|
+
*/
|
|
25
|
+
export abstract class TextureUsageTracker {
|
|
26
|
+
constructor(protected releaseCallback: (textureDescId: number) => void) {}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Register a texture with the tracker.
|
|
30
|
+
*
|
|
31
|
+
* @param texture
|
|
32
|
+
*/
|
|
33
|
+
abstract registerTexture(texture: TextureRef): void;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Increment the reference count for a texture.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* This should be called anytime a Node sets a new texture.
|
|
40
|
+
*
|
|
41
|
+
* @param texture
|
|
42
|
+
*/
|
|
43
|
+
abstract incrementTextureRefCount(texture: TextureRef): void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Decrement the Node reference count for a texture.
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* This should be called anytime a Node removes a texture.
|
|
50
|
+
*
|
|
51
|
+
* @param texture
|
|
52
|
+
*/
|
|
53
|
+
abstract decrementTextureRefCount(texture: TextureRef): void;
|
|
54
|
+
}
|