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.7 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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"}