{"version":3,"file":"GCSystem.mjs","sources":["../../../../src/rendering/renderers/shared/GCSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../extensions/Extensions';\nimport { type RenderGroup } from '../../../scene/container/RenderGroup';\nimport { cleanArray, cleanHash } from '../../../utils/data/clean';\nimport { type GPUDataOwner, type Renderer } from '../types';\nimport { type Renderable } from './Renderable';\nimport { type RenderOptions } from './system/AbstractRenderer';\n\nimport type EventEmitter from 'eventemitter3';\nimport type { System } from './system/System';\n\n/**\n * Data stored on a GC-managed resource.\n * @category rendering\n * @advanced\n */\nexport interface GCData\n{\n    /** Index in the managed resources array */\n    index?: number;\n    /** Type of the resource */\n    type: 'resource' | 'renderable';\n}\n\n/**\n * Interface for resources that can be garbage collected.\n * @category rendering\n * @advanced\n */\nexport interface GCable extends GPUDataOwner\n{\n    /** Timestamp of last use */\n    _gcLastUsed: number;\n    /** GC tracking data, null if not being tracked */\n    _gcData?: GCData | null;\n    /** If set to true, the resource will be garbage collected automatically when it is not used. */\n    autoGarbageCollect?: boolean;\n    /** An optional callback for when an item is touched */\n    _onTouch?(now: number): void;\n}\n\ntype GCableEventEmitter = GCable & Pick<EventEmitter, 'once' | 'off'>;\n\ninterface GCResourceHashEntry\n{\n    context: any;\n    hash: string;\n    type: GCData['type'];\n    priority: number;\n}\n\n/**\n * Options for the {@link GCSystem}.\n * @category rendering\n * @advanced\n */\nexport interface GCSystemOptions\n{\n    /**\n     * If set to true, this will enable the garbage collector.\n     * @default true\n     */\n    gcActive: boolean;\n    /**\n     * The maximum time in milliseconds a resource can be unused before being garbage collected.\n     * @default 60000\n     */\n    gcMaxUnusedTime: number;\n    /**\n     * How frequently to run garbage collection in milliseconds.\n     * @default 30000\n     */\n    gcFrequency: number;\n}\n\n/**\n * A unified garbage collection system for managing GPU resources.\n * Resources register themselves with a cleanup callback and are automatically\n * cleaned up when they haven't been used for a specified amount of time.\n * @example\n * ```ts\n * // Register a resource for GC\n * gc.addResource(myResource, () => {\n *     // cleanup logic here\n *     myResource.unload();\n * });\n *\n * // Touch the resource when used (resets idle timer)\n * gc.touch(myResource);\n *\n * // Remove from GC tracking (e.g., on manual destroy)\n * gc.removeResource(myResource);\n * ```\n * @category rendering\n * @advanced\n */\nexport class GCSystem implements System<GCSystemOptions>\n{\n    /** @ignore */\n    public static extension = {\n        type: [\n            ExtensionType.WebGLSystem,\n            ExtensionType.WebGPUSystem,\n            ExtensionType.CanvasSystem,\n        ],\n        name: 'gc',\n        priority: 0,\n    } as const;\n\n    /** Default options for the GCSystem */\n    public static defaultOptions: GCSystemOptions = {\n        /** Enable/disable the garbage collector */\n        gcActive: true,\n        /** Time in ms before an unused resource is collected (default 1 minute) */\n        gcMaxUnusedTime: 60000,\n        /** How often to run garbage collection in ms (default 30 seconds) */\n        gcFrequency: 30000,\n    };\n\n    /** Maximum time in ms a resource can be unused before being garbage collected */\n    public maxUnusedTime: number;\n\n    /** Reference to the renderer this system belongs to */\n    private _renderer: Renderer;\n\n    /** Array of resources being tracked for garbage collection */\n    private readonly _managedResources: GCableEventEmitter[] = [];\n    private readonly _managedResourceHashes: GCResourceHashEntry[] = [];\n    private readonly _managedCollections: {context: any, collection: string, type: 'hash' | 'array'}[] = [];\n\n    /** ID of the GC scheduler handler */\n    private _handler: number;\n    private _collectionsHandler: number;\n\n    /** How frequently GC runs in ms */\n    private _frequency: number;\n\n    /** Current timestamp used for age calculations */\n    public now: number;\n\n    private _ready = false;\n\n    /**\n     * Creates a new GCSystem instance.\n     * @param renderer - The renderer this garbage collection system works for\n     */\n    constructor(renderer: Renderer)\n    {\n        this._renderer = renderer;\n    }\n\n    /**\n     * Initializes the garbage collection system with the provided options.\n     * @param options - Configuration options\n     */\n    public init(options: GCSystemOptions): void\n    {\n        options = { ...GCSystem.defaultOptions, ...options };\n\n        this.maxUnusedTime = options.gcMaxUnusedTime;\n        this._frequency = options.gcFrequency;\n\n        this.enabled = options.gcActive;\n        this.now = performance.now();\n    }\n\n    /**\n     * Gets whether the garbage collection system is currently enabled.\n     * @returns True if GC is enabled, false otherwise\n     */\n    get enabled(): boolean\n    {\n        return !!this._handler;\n    }\n\n    /**\n     * Enables or disables the garbage collection system.\n     * When enabled, schedules periodic cleanup of resources.\n     * When disabled, cancels all scheduled cleanups.\n     */\n    set enabled(value: boolean)\n    {\n        if (this.enabled === value) return;\n\n        if (value)\n        {\n            this._handler = this._renderer.scheduler.repeat(\n                () =>\n                {\n                    this._ready = true;\n                },\n                this._frequency,\n                false\n            );\n            // Schedule periodic hash table cleanup\n            this._collectionsHandler = this._renderer.scheduler.repeat(\n                () =>\n                {\n                    for (const hash of this._managedCollections)\n                    {\n                        const { context, collection, type } = hash;\n\n                        if (type === 'hash')\n                        {\n                            context[collection] = cleanHash(context[collection]);\n                        }\n                        else\n                        {\n                            context[collection] = cleanArray(context[collection]);\n                        }\n                    }\n                },\n                this._frequency\n            );\n        }\n        else\n        {\n            this._renderer.scheduler.cancel(this._handler);\n            this._renderer.scheduler.cancel(this._collectionsHandler);\n            this._handler = 0;\n            this._collectionsHandler = 0;\n        }\n    }\n\n    /**\n     * Called before rendering. Updates the current timestamp.\n     * @param options - The render options\n     * @param options.container - The container to render\n     */\n    protected prerender({ container }: RenderOptions): void\n    {\n        this.now = performance.now();\n        container.renderGroup.gcTick = this._renderer.tick++;\n\n        this._updateInstructionGCTick(container.renderGroup, container.renderGroup.gcTick);\n    }\n\n    /** Performs garbage collection after rendering. */\n    protected postrender(): void\n    {\n        if (!this._ready || !this.enabled) return;\n\n        this.run();\n        this._ready = false;\n    }\n\n    /**\n     * Updates the GC tick counter for a render group and its children.\n     * @param renderGroup - The render group to update\n     * @param gcTick - The new tick value\n     */\n    private _updateInstructionGCTick(renderGroup: RenderGroup, gcTick: number): void\n    {\n        renderGroup.instructionSet.gcTick = gcTick;\n        renderGroup.gcTick = gcTick;\n\n        for (const child of renderGroup.renderGroupChildren)\n        {\n            this._updateInstructionGCTick(child, gcTick);\n        }\n    }\n\n    /**\n     * Registers a collection for garbage collection tracking.\n     * @param context - The object containing the collection\n     * @param collection - The property name on context that holds the collection\n     * @param type - The type of collection to track ('hash' or 'array')\n     */\n    public addCollection(context: any, collection: string, type: 'hash' | 'array'): void\n    {\n        this._managedCollections.push({\n            context,\n            collection,\n            type,\n        });\n    }\n\n    /**\n     * Registers a resource for garbage collection tracking.\n     * @param resource - The resource to track\n     * @param type - The type of resource to track\n     */\n    public addResource(resource: GCableEventEmitter, type: GCData['type']): void\n    {\n        // Already being tracked\n        if (resource._gcLastUsed !== -1)\n        {\n            resource._gcLastUsed = this.now;\n            resource._onTouch?.(this.now);\n\n            return;\n        }\n\n        const index = this._managedResources.length;\n\n        resource._gcData = {\n            index,\n            type,\n        };\n        resource._gcLastUsed = this.now;\n        resource._onTouch?.(this.now);\n        resource.once('unload', this.removeResource, this);\n\n        this._managedResources.push(resource);\n    }\n\n    /**\n     * Removes a resource from garbage collection tracking.\n     * Call this when manually destroying a resource.\n     * @param resource - The resource to stop tracking\n     */\n    public removeResource(resource: GCable): void\n    {\n        const gcData = resource._gcData;\n\n        if (!gcData) return;\n\n        const index = gcData.index;\n        const last = this._managedResources.length - 1;\n\n        // Swap with last element for O(1) removal\n        if (index !== last)\n        {\n            const lastResource = this._managedResources[last];\n\n            this._managedResources[index] = lastResource;\n            lastResource._gcData.index = index;\n        }\n\n        this._managedResources.length--;\n        resource._gcData = null;\n        resource._gcLastUsed = -1;\n    }\n\n    /**\n     * Registers a hash-based resource collection for garbage collection tracking.\n     * Resources in the hash will be automatically tracked and cleaned up when unused.\n     * @param context - The object containing the hash property\n     * @param hash - The property name on context that holds the resource hash\n     * @param type - The type of resources in the hash ('resource' or 'renderable')\n     * @param priority - Processing priority (lower values are processed first)\n     */\n    public addResourceHash(context: any, hash: string, type: GCData['type'], priority: number = 0): void\n    {\n        this._managedResourceHashes.push({\n            context,\n            hash,\n            type,\n            priority,\n        });\n\n        this._managedResourceHashes.sort((a, b) => a.priority - b.priority);\n    }\n\n    /**\n     * Performs garbage collection by cleaning up unused resources.\n     * Removes resources that haven't been used for longer than maxUnusedTime.\n     */\n    public run(): void\n    {\n        const now = performance.now();\n        const managedResourceHashes = this._managedResourceHashes;\n\n        for (const hashEntry of managedResourceHashes)\n        {\n            this.runOnHash(hashEntry, now);\n        }\n\n        let writeIndex = 0;\n\n        for (let i = 0; i < this._managedResources.length; i++)\n        {\n            const resource = this._managedResources[i];\n\n            writeIndex = this.runOnResource(resource, now, writeIndex);\n        }\n\n        this._managedResources.length = writeIndex;\n    }\n\n    protected updateRenderableGCTick(renderable: Renderable & GCable, now: number): void\n    {\n        const renderGroup = renderable.renderGroup ?? renderable.parentRenderGroup;\n        const currentTick = renderGroup?.instructionSet?.gcTick ?? -1;\n\n        // Update last used time if the renderable's group was rendered this tick\n        if ((renderGroup?.gcTick ?? 0) === currentTick)\n        {\n            renderable._gcLastUsed = now;\n            renderable._onTouch?.(now);\n        }\n    }\n\n    protected runOnResource(resource: GCableEventEmitter, now: number, writeIndex: number): number\n    {\n        const gcData = resource._gcData;\n\n        // special case for renderables as we do not check every frame if they are being used\n        if (gcData.type === 'renderable')\n        {\n            this.updateRenderableGCTick(resource as Renderable, now);\n        }\n\n        const isRecentlyUsed = now - resource._gcLastUsed < this.maxUnusedTime;\n\n        if (isRecentlyUsed || !resource.autoGarbageCollect)\n        {\n            this._managedResources[writeIndex] = resource;\n            gcData.index = writeIndex;\n            writeIndex++;\n        }\n        else\n        {\n            // Call the cleanup function\n            resource.unload();\n            resource._gcData = null;\n            resource._gcLastUsed = -1;\n            resource.off('unload', this.removeResource, this);\n        }\n\n        return writeIndex;\n    }\n\n    /**\n     * Creates a clone of the hash, copying all non-null entries up to (but not including) the stop key.\n     * @param hashValue - The original hash to clone from\n     * @param stopKey - The key to stop at (exclusive)\n     * @returns A new hash object with copied entries\n     */\n    private _createHashClone(hashValue: Record<string, GCable>, stopKey: string): Record<string, GCable>\n    {\n        const hashClone: Record<string, GCable> = Object.create(null);\n\n        for (const k in hashValue)\n        {\n            if (k === stopKey) break;\n            if (hashValue[k] !== null) hashClone[k] = hashValue[k];\n        }\n\n        return hashClone;\n    }\n\n    protected runOnHash(hashEntry: GCResourceHashEntry, now: number): void\n    {\n        const { context, hash, type } = hashEntry;\n\n        const hashValue = context[hash] as Record<string, GCable>;\n        let hashClone: Record<string, GCable> | null = null;\n        let nullCount = 0;\n\n        for (const key in hashValue)\n        {\n            const resource = hashValue[key];\n\n            // check if the value is null\n            if (resource === null)\n            {\n                nullCount++;\n\n                // Lazily create the clone to clean up null entries when threshold is reached\n                if (nullCount === 10000 && !hashClone)\n                {\n                    hashClone = this._createHashClone(hashValue, key);\n                }\n\n                continue;\n            }\n\n            // If no GC data, then the resource has been added since the last garbage collection\n            if (resource._gcLastUsed === -1)\n            {\n                resource._gcLastUsed = now;\n                resource._onTouch?.(now);\n\n                if (hashClone) hashClone[key] = resource;\n\n                continue;\n            }\n\n            // special case for renderables as we do not check every frame if they are being used\n            if (type === 'renderable')\n            {\n                this.updateRenderableGCTick(resource as Renderable, now);\n            }\n\n            const isRecentlyUsed = now - resource._gcLastUsed < this.maxUnusedTime;\n\n            if (!isRecentlyUsed && resource.autoGarbageCollect)\n            {\n                // Lazily create the clone only when we need to remove something\n                if (!hashClone)\n                {\n                    // we can set the value to null here to avoid having to create a new hash object\n                    // only when it crosses the 10000 threshold do we need to create a new hash object\n                    if (nullCount + 1 !== 10000)\n                    {\n                        hashValue[key] = null;\n                        nullCount++;\n                    }\n                    else\n                    {\n                        hashClone = this._createHashClone(hashValue, key);\n                    }\n                }\n\n                if (type === 'renderable')\n                {\n                    const res = resource as Renderable;\n                    const renderGroup = res.renderGroup ?? res.parentRenderGroup;\n\n                    if (renderGroup) renderGroup.structureDidChange = true;\n                }\n\n                // Call the cleanup function\n                resource.unload();\n                resource._gcData = null;\n                resource._gcLastUsed = -1;\n            }\n            else if (hashClone)\n            {\n                hashClone[key] = resource;\n            }\n        }\n\n        // Only replace the hash if something was removed\n        if (hashClone)\n        {\n            context[hash] = hashClone;\n        }\n    }\n\n    /** Cleans up the garbage collection system. Disables GC and removes all tracked resources. */\n    public destroy(): void\n    {\n        this.enabled = false;\n\n        this._managedResources.forEach((resource) =>\n        {\n            resource.off('unload', this.removeResource, this);\n        });\n        this._managedResources.length = 0;\n        this._managedResourceHashes.length = 0;\n        this._managedCollections.length = 0;\n        this._renderer = null as any as Renderer;\n    }\n}\n"],"names":[],"mappings":"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"}