UNPKG

pixi.js

Version:

<p align="center"> <a href="https://pixijs.com" target="_blank" rel="noopener noreferrer"> <img height="150" src="https://files.pixijs.download/branding/pixijs-logo-transparent-dark.svg?v=1" alt="PixiJS logo"> </a> </p> <br/> <p align="center">

1 lines 23.1 kB
{"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 { 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 ],\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\n /** ID of the GC scheduler handler */\n private _handler: 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 }\n else\n {\n this._renderer.scheduler.cancel(this._handler);\n this._handler = 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\n for (const child of renderGroup.renderGroupChildren)\n {\n this._updateInstructionGCTick(child, gcTick);\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 // 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._renderer = null as any as Renderer;\n }\n}\n\n"],"names":[],"mappings":"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"}