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 12.9 kB
{"version":3,"file":"WorkerManager.mjs","sources":["../../../../src/assets/loader/workers/WorkerManager.ts"],"sourcesContent":["import CheckImageBitmapWorker from 'worker:./checkImageBitmap.worker.ts';\nimport LoadImageBitmapWorker from 'worker:./loadImageBitmap.worker.ts';\n\nimport type { TextureSourceOptions } from '../../../rendering/renderers/shared/texture/sources/TextureSource';\nimport type { ResolvedAsset } from '../../types';\n\nlet UUID = 0;\nlet MAX_WORKERS: number;\n\ntype LoadImageBitmapResult = {\n data?: ImageBitmap,\n error?: Error,\n uuid: number,\n id: string,\n};\n\n/** @internal */\nclass WorkerManagerClass\n{\n /**\n * Hash map storing resolve/reject functions for pending worker requests.\n * Keyed by UUID to match responses with their corresponding promises.\n */\n private _resolveHash: {\n [key: string]: {\n resolve: (...param: any[]) => void;\n reject: (...param: any[]) => void;\n }\n };\n /** Pool of available workers ready for use */\n private readonly _workerPool: Worker[];\n /** Queue of pending work items waiting for available workers */\n private readonly _queue: {\n id: string;\n arguments: any[];\n resolve: (...param: any[]) => void;\n reject: (...param: any[]) => void;\n }[];\n\n /** Whether the worker manager has been initialized */\n private _initialized = false;\n\n /** Current number of created workers (used to enforce MAX_WORKERS limit) */\n private _createdWorkers = 0;\n /** Cached promise for ImageBitmap support check */\n private _isImageBitmapSupported?: Promise<boolean>;\n\n constructor()\n {\n this._workerPool = [];\n this._queue = [];\n\n this._resolveHash = {};\n }\n\n /**\n * Checks if ImageBitmap is supported in the current environment.\n *\n * This method uses a dedicated worker to test ImageBitmap support\n * and caches the result for subsequent calls.\n * @returns Promise that resolves to true if ImageBitmap is supported, false otherwise\n */\n public isImageBitmapSupported(): Promise<boolean>\n {\n if (this._isImageBitmapSupported !== undefined) return this._isImageBitmapSupported;\n\n this._isImageBitmapSupported = new Promise((resolve) =>\n {\n const { worker } = new CheckImageBitmapWorker();\n\n worker.addEventListener('message', (event: MessageEvent<boolean>) =>\n {\n worker.terminate();\n CheckImageBitmapWorker.revokeObjectURL();\n resolve(event.data);\n });\n });\n\n return this._isImageBitmapSupported;\n }\n\n /**\n * Loads an image as an ImageBitmap using a web worker.\n * @param src - The source URL or path of the image to load\n * @param asset - Optional resolved asset containing additional texture source options\n * @returns Promise that resolves to the loaded ImageBitmap\n * @example\n * ```typescript\n * const bitmap = await WorkerManager.loadImageBitmap('image.png');\n * const bitmapWithOptions = await WorkerManager.loadImageBitmap('image.png', asset);\n * ```\n */\n public loadImageBitmap(src: string, asset?: ResolvedAsset<TextureSourceOptions<any>>): Promise<ImageBitmap>\n {\n return this._run('loadImageBitmap', [src, asset?.data?.alphaMode]) as Promise<ImageBitmap>;\n }\n\n /**\n * Initializes the worker pool if not already initialized.\n * Currently a no-op but reserved for future initialization logic.\n */\n private async _initWorkers()\n {\n if (this._initialized) return;\n\n this._initialized = true;\n }\n\n /**\n * Gets an available worker from the pool or creates a new one if needed.\n *\n * Workers are created up to the MAX_WORKERS limit (based on navigator.hardwareConcurrency).\n * Each worker is configured with a message handler for processing results.\n * @returns Available worker or undefined if pool is at capacity and no workers are free\n */\n private _getWorker(): Worker\n {\n if (MAX_WORKERS === undefined)\n {\n MAX_WORKERS = navigator.hardwareConcurrency || 4;\n }\n let worker = this._workerPool.pop();\n\n if (!worker && this._createdWorkers < MAX_WORKERS)\n {\n // only create as many as MAX_WORKERS allows..\n this._createdWorkers++;\n worker = new LoadImageBitmapWorker().worker;\n\n worker.addEventListener('message', (event: MessageEvent) =>\n {\n this._complete(event.data);\n\n this._returnWorker(event.target as Worker);\n this._next();\n });\n }\n\n return worker;\n }\n\n /**\n * Returns a worker to the pool after completing a task.\n * @param worker - The worker to return to the pool\n */\n private _returnWorker(worker: Worker)\n {\n this._workerPool.push(worker);\n }\n\n /**\n * Handles completion of a worker task by resolving or rejecting the corresponding promise.\n * @param data - Result data from the worker containing uuid, data, and optional error\n */\n private _complete(data: LoadImageBitmapResult): void\n {\n if (!this._resolveHash[data.uuid])\n {\n // this can happen if the worker manager is reset before a task completes\n return;\n }\n\n if (data.error !== undefined)\n {\n this._resolveHash[data.uuid].reject(data.error);\n }\n else\n {\n this._resolveHash[data.uuid].resolve(data.data);\n }\n\n delete this._resolveHash[data.uuid];\n }\n\n /**\n * Executes a task using the worker pool system.\n *\n * Queues the task and processes it when a worker becomes available.\n * @param id - Identifier for the type of task to run\n * @param args - Arguments to pass to the worker\n * @returns Promise that resolves with the worker's result\n */\n private async _run(id: string, args: any[]): Promise<any>\n {\n await this._initWorkers();\n // push into the queue...\n\n const promise = new Promise((resolve, reject) =>\n {\n this._queue.push({ id, arguments: args, resolve, reject });\n });\n\n this._next();\n\n return promise;\n }\n\n /**\n * Processes the next item in the queue if workers are available.\n *\n * This method is called after worker initialization and when workers\n * complete tasks to continue processing the queue.\n */\n private _next(): void\n {\n // nothing to do\n if (!this._queue.length) return;\n\n const worker = this._getWorker();\n\n // no workers available...\n if (!worker)\n {\n return;\n }\n\n const toDo = this._queue.pop();\n\n const id = toDo.id;\n\n this._resolveHash[UUID] = { resolve: toDo.resolve, reject: toDo.reject };\n\n worker.postMessage({\n data: toDo.arguments,\n uuid: UUID++,\n id,\n });\n }\n\n /**\n * Resets the worker manager, terminating all workers and clearing the queue.\n *\n * This method:\n * - Terminates all active workers\n * - Rejects all pending promises with an error\n * - Clears all internal state\n * - Resets initialization flags\n *\n * This should be called when the worker manager is no longer needed\n * to prevent memory leaks and ensure proper cleanup.\n * @example\n * ```typescript\n * // Clean up when shutting down\n * WorkerManager.reset();\n * ```\n */\n public reset(): void\n {\n // Terminate all workers\n this._workerPool.forEach((worker) => worker.terminate());\n this._workerPool.length = 0;\n\n // Reject pending promises\n Object.values(this._resolveHash).forEach(({ reject }) =>\n {\n reject?.(new Error('WorkerManager has been reset before completion'));\n });\n this._resolveHash = {};\n this._queue.length = 0;\n\n this._initialized = false;\n this._createdWorkers = 0;\n }\n}\n\n/**\n * Manages a pool of web workers for loading ImageBitmap objects asynchronously.\n *\n * This class provides a thread-safe way to load images using web workers,\n * automatically managing worker creation, pooling, and cleanup. It supports\n * checking ImageBitmap support and queuing multiple load requests.\n *\n * > [!IMPORTANT] You should not need to use this class directly\n * > However, you can call `WorkerManager.reset()` to clean up all workers when they are no longer needed.\n * @category Assets\n * @advanced\n */\nconst WorkerManager = new WorkerManagerClass();\n\nexport {\n WorkerManager,\n};\n"],"names":["CheckImageBitmapWorker","LoadImageBitmapWorker"],"mappings":"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"}