115 lines
3.4 KiB
JavaScript
115 lines
3.4 KiB
JavaScript
import { ExtensionType } from '../../../../extensions/Extensions.mjs';
|
|
|
|
"use strict";
|
|
const _RenderableGCSystem = class _RenderableGCSystem {
|
|
/** @param renderer - The renderer this System works for. */
|
|
constructor(renderer) {
|
|
this._managedRenderables = [];
|
|
this._renderer = renderer;
|
|
}
|
|
init(options) {
|
|
options = { ..._RenderableGCSystem.defaultOptions, ...options };
|
|
this.maxUnusedTime = options.renderableGCMaxUnusedTime;
|
|
this._frequency = options.renderableGCFrequency;
|
|
this.enabled = options.renderableGCActive;
|
|
}
|
|
get enabled() {
|
|
return !!this._handler;
|
|
}
|
|
set enabled(value) {
|
|
if (this.enabled === value)
|
|
return;
|
|
if (value) {
|
|
this._handler = this._renderer.scheduler.repeat(
|
|
() => this.run(),
|
|
this._frequency
|
|
);
|
|
} else {
|
|
this._renderer.scheduler.cancel(this._handler);
|
|
}
|
|
}
|
|
prerender() {
|
|
this._now = performance.now();
|
|
}
|
|
addRenderable(renderable, instructionSet) {
|
|
if (!this.enabled)
|
|
return;
|
|
renderable._lastUsed = this._now;
|
|
if (renderable._lastInstructionTick === -1) {
|
|
this._managedRenderables.push(renderable);
|
|
renderable.once("destroyed", this._removeRenderable, this);
|
|
}
|
|
renderable._lastInstructionTick = instructionSet.tick;
|
|
}
|
|
/** Runs the scheduled garbage collection */
|
|
run() {
|
|
const now = performance.now();
|
|
const managedRenderables = this._managedRenderables;
|
|
const renderPipes = this._renderer.renderPipes;
|
|
let offset = 0;
|
|
for (let i = 0; i < managedRenderables.length; i++) {
|
|
const renderable = managedRenderables[i];
|
|
if (renderable === null) {
|
|
offset++;
|
|
continue;
|
|
}
|
|
const renderGroup = renderable.renderGroup ?? renderable.parentRenderGroup;
|
|
const currentIndex = renderGroup?.instructionSet?.tick ?? -1;
|
|
if (renderable._lastInstructionTick !== currentIndex && now - renderable._lastUsed > this.maxUnusedTime) {
|
|
if (!renderable.destroyed) {
|
|
const rp = renderPipes;
|
|
rp[renderable.renderPipeId].destroyRenderable(renderable);
|
|
}
|
|
renderable._lastInstructionTick = -1;
|
|
offset++;
|
|
renderable.off("destroyed", this._removeRenderable, this);
|
|
} else {
|
|
managedRenderables[i - offset] = renderable;
|
|
}
|
|
}
|
|
managedRenderables.length = managedRenderables.length - offset;
|
|
}
|
|
destroy() {
|
|
this.enabled = false;
|
|
this._renderer = null;
|
|
this._managedRenderables.length = 0;
|
|
}
|
|
_removeRenderable(renderable) {
|
|
const index = this._managedRenderables.indexOf(renderable);
|
|
if (index >= 0) {
|
|
renderable.off("destroyed", this._removeRenderable, this);
|
|
this._managedRenderables[index] = null;
|
|
}
|
|
}
|
|
};
|
|
/** @ignore */
|
|
_RenderableGCSystem.extension = {
|
|
type: [
|
|
ExtensionType.WebGLSystem,
|
|
ExtensionType.WebGPUSystem
|
|
],
|
|
name: "renderableGC"
|
|
};
|
|
/** default options for the renderableGCSystem */
|
|
_RenderableGCSystem.defaultOptions = {
|
|
/**
|
|
* If set to true, this will enable the garbage collector on the GPU.
|
|
* @default true
|
|
*/
|
|
renderableGCActive: true,
|
|
/**
|
|
* The maximum idle frames before a texture is destroyed by garbage collection.
|
|
* @default 60 * 60
|
|
*/
|
|
renderableGCMaxUnusedTime: 6e4,
|
|
/**
|
|
* Frames between two garbage collections.
|
|
* @default 600
|
|
*/
|
|
renderableGCFrequency: 3e4
|
|
};
|
|
let RenderableGCSystem = _RenderableGCSystem;
|
|
|
|
export { RenderableGCSystem };
|
|
//# sourceMappingURL=RenderableGCSystem.mjs.map
|