diff --git a/examples/jsm/loaders/OBJLoader2.d.ts b/examples/jsm/loaders/OBJLoader2.d.ts index e0b66095f59ff8..f55e3d18c6eaea 100644 --- a/examples/jsm/loaders/OBJLoader2.d.ts +++ b/examples/jsm/loaders/OBJLoader2.d.ts @@ -13,7 +13,6 @@ export class OBJLoader2 extends Loader { constructor( manager?: LoadingManager ); parser: OBJLoader2Parser; modelName: string; - instanceNo: number; path: string; resourcePath: string; baseObject3d: Object3D; diff --git a/examples/jsm/loaders/OBJLoader2.js b/examples/jsm/loaders/OBJLoader2.js index 1fbe343b2fb024..1764c626bda9bc 100644 --- a/examples/jsm/loaders/OBJLoader2.js +++ b/examples/jsm/loaders/OBJLoader2.js @@ -26,7 +26,6 @@ const OBJLoader2 = function ( manager ) { this.parser = new OBJLoader2Parser(); this.modelName = ''; - this.instanceNo = 0; this.baseObject3d = new Object3D(); this.materialHandler = new MaterialHandler(); diff --git a/examples/jsm/loaders/OBJLoader2Parallel.js b/examples/jsm/loaders/OBJLoader2Parallel.js index 487162dbc3a273..d3db441a561404 100644 --- a/examples/jsm/loaders/OBJLoader2Parallel.js +++ b/examples/jsm/loaders/OBJLoader2Parallel.js @@ -24,12 +24,11 @@ const OBJLoader2Parallel = function ( manager ) { OBJLoader2.call( this, manager ); this.preferJsmWorker = false; - this.initPerformed = false; this.jsmWorkerUrl = null; this.executeParallel = true; - this.taskManager = new TaskManager(); + this.taskManager = null; this.taskName = 'tmOBJLoader2'; }; @@ -101,6 +100,12 @@ OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototyp */ _buildWorkerCode: async function () { + if ( ! this.taskManager instanceof TaskManager ) { + + if ( this.parser.logging.debug ) console.log( 'Needed to create new TaskManager' ); + this.taskManager = new TaskManager(); + + } if ( ! this.taskManager.supportsTaskType( this.taskName ) ) { if ( this.preferJsmWorker ) { @@ -110,19 +115,13 @@ OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototyp } else { let obj2ParserDep = 'const OBJLoader2Parser = ' + OBJLoader2Parser.toString() + ';\n\n'; - this.taskManager.registerTaskType( this.taskName, OBJ2LoaderWorker.init, OBJ2LoaderWorker.execute, null, false, [{ code: obj2ParserDep }] ); + this.taskManager.registerTaskType( this.taskName, OBJ2LoaderWorker.init, OBJ2LoaderWorker.execute, null, false, + [{ code: obj2ParserDep }] ); } - await this.taskManager.initTaskType( this.taskName, {} ).catch( e => console.error( e ) ); - - } - else { - - await new Promise( resolve => resolve( true ) ); + await this.taskManager.initTaskType( this.taskName, {} ); } - this.initPerformed = true; - return this.initPerformed; }, @@ -149,7 +148,6 @@ OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototyp } } - OBJLoader2.prototype.load.call( this, content, interceptOnLoad, onFileLoadProgress, onError, onMeshAlter ); }, @@ -163,21 +161,14 @@ OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototyp if ( this.executeParallel ) { - // check if worker has been initialize before. If yes, skip init - if ( ! this.initPerformed ) { - - this._buildWorkerCode() - .then( x => { + this._buildWorkerCode() + .then( + x => { if ( this.parser.logging.debug ) console.log( 'OBJLoader2Parallel init was performed: ' + x ); - this._executeWorkerParse( content ) - } ); + this._executeWorkerParse( content ); + } + ).catch( e => console.error( e ) ); - } - else { - - this._executeWorkerParse( content ); - - } let dummy = new Object3D(); dummy.name = 'OBJLoader2ParallelDummy'; return dummy; @@ -196,23 +187,22 @@ OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototyp this.materialHandler.createDefaultMaterials( false ); let config = { - id: 42, + id: Math.floor( Math.random() * Math.floor( 65536 ) ), + buffer: content, params: { modelName: this.modelName, - instanceNo: this.instanceNo, useIndices: this.parser.useIndices, disregardNormals: this.parser.disregardNormals, materialPerSmoothingGroup: this.parser.materialPerSmoothingGroup, useOAsMesh: this.parser.useOAsMesh, materials: this.materialHandler.getMaterialsJSON() }, - buffer: content, logging: { enabled: this.parser.logging.enabled, debug: this.parser.logging.debug } }; - this.taskManager.enqueueForExecution( this.taskName, config,data => this._onAssetAvailable( data ), { buffer: content.buffer } ) + this.taskManager.enqueueForExecution( this.taskName, config, data => this._onAssetAvailable( data ), { buffer: content } ) .then( data => { this._onAssetAvailable( data ); this.parser.callbacks.onLoad( this.baseObject3d, 'finished' ); @@ -222,8 +212,6 @@ OBJLoader2Parallel.prototype = Object.assign( Object.create( OBJLoader2.prototyp } - - } ); export { OBJLoader2Parallel }; diff --git a/examples/jsm/loaders/obj2/OBJLoader2Parser.js b/examples/jsm/loaders/obj2/OBJLoader2Parser.js index 9b53f1731049c9..c28da78862606d 100644 --- a/examples/jsm/loaders/obj2/OBJLoader2Parser.js +++ b/examples/jsm/loaders/obj2/OBJLoader2Parser.js @@ -1,4 +1,5 @@ /** + * @author Kai Salmen / https://kaisalmen.de * Development repository: https://github.com/kaisalmen/WWOBJLoader */ @@ -7,11 +8,6 @@ */ const OBJLoader2Parser = function () { - this.logging = { - enabled: false, - debug: false - }; - const scope = this; this.callbacks = { @@ -60,54 +56,65 @@ const OBJLoader2Parser = function () { } }; - this.contentRef = null; - this.legacyMode = false; - - this.materials = {}; - this.materialPerSmoothingGroup = false; - this.useOAsMesh = false; - this.useIndices = false; - this.disregardNormals = false; - - this.vertices = []; - this.colors = []; - this.normals = []; - this.uvs = []; - this.objectId = 0; - - this.rawMesh = { - objectName: '', - groupName: '', - activeMtlName: '', - mtllibName: '', - - // reset with new mesh - faceType: - 1, - subGroups: [], - subGroupInUse: null, - smoothingGroup: { - splitMaterials: false, - normalized: - 1, - real: - 1 - }, - counts: { + + this._init = function () { + + this.logging = { + enabled: false, + debug: false + }; + + this.contentRef = null; + this.legacyMode = false; + + this.materials = {}; + this.materialPerSmoothingGroup = false; + this.useOAsMesh = false; + this.useIndices = false; + this.disregardNormals = false; + + this.vertices = []; + this.colors = []; + this.normals = []; + this.uvs = []; + this.objectId = 0; + + this.rawMesh = { + objectName: '', + groupName: '', + activeMtlName: '', + mtllibName: '', + + // reset with new mesh + faceType: - 1, + subGroups: [], + subGroupInUse: null, + smoothingGroup: { + splitMaterials: false, + normalized: - 1, + real: - 1 + }, + counts: { + doubleIndicesCount: 0, + faceCount: 0, + mtlCount: 0, + smoothingGroupCount: 0 + } + }; + + this.inputObjectCount = 1; + this.outputObjectCount = 1; + this.globalCounts = { + vertices: 0, + faces: 0, doubleIndicesCount: 0, - faceCount: 0, - mtlCount: 0, - smoothingGroupCount: 0 - } - }; + lineByte: 0, + currentByte: 0, + totalBytes: 0 + }; - this.inputObjectCount = 1; - this.outputObjectCount = 1; - this.globalCounts = { - vertices: 0, - faces: 0, - doubleIndicesCount: 0, - lineByte: 0, - currentByte: 0, - totalBytes: 0 - }; + } + this._init(); this._resetRawMesh = function () { @@ -842,12 +849,6 @@ const OBJLoader2Parser = function () { this._resetRawMesh(); } - this.callbacks.onAssetAvailable( - { - cmd: 'execComplete', - type: 'void' - } ); - return haveMesh; } @@ -940,6 +941,7 @@ const OBJLoader2Parser = function () { const payload = { cmd: 'assetAvailable', type: 'material', + id: this.objectId, materials: { materialCloneInstructions: materialCloneInstructions } @@ -1070,11 +1072,11 @@ const OBJLoader2Parser = function () { uvs: uvFA } }, - [ vertexFA.buffer ], - indexUA !== null ? [ indexUA.buffer ] : null, - colorFA !== null ? [ colorFA.buffer ] : null, - normalFA !== null ? [ normalFA.buffer ] : null, - uvFA !== null ? [ uvFA.buffer ] : null + [ vertexFA.buffer, + indexUA !== null ? indexUA.buffer : null, + colorFA !== null ? colorFA.buffer : null, + normalFA !== null ? normalFA.buffer : null, + uvFA !== null ? uvFA.buffer : null ] ); } @@ -1091,6 +1093,12 @@ const OBJLoader2Parser = function () { console.info( parserFinalReport ); } + this.callbacks.onAssetAvailable( + { + cmd: 'execComplete', + type: 'void', + id: this.objectId + } ); } }; diff --git a/examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts b/examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts index 134441c0967b48..ded53965ee33b8 100644 --- a/examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts +++ b/examples/jsm/loaders/obj2/shared/MaterialHandler.d.ts @@ -1,26 +1,2 @@ -import { - Material -} from '../../../../../src/Three'; - export class MaterialHandler { - - constructor(); - logging: { - enabled: boolean; - debug: boolean; - }; - callbacks: { - onLoadMaterials: Function; - }; - materials: object; - - createDefaultMaterials( overrideExisting: boolean ): void; - addMaterials( materials: object, overrideExisting: boolean, newMaterials?: object ): object; - addPayloadMaterials( materialPayload: object ): object; - setLogging( enabled: boolean, debug: boolean ): void; - getMaterials(): object; - getMaterial( materialName: string ): Material; - getMaterialsJSON(): object; - clearMaterials(): void; - } diff --git a/examples/jsm/loaders/obj2/shared/MaterialHandler.js b/examples/jsm/loaders/obj2/shared/MaterialHandler.js index 443965c0e91f74..5e610336c74242 100644 --- a/examples/jsm/loaders/obj2/shared/MaterialHandler.js +++ b/examples/jsm/loaders/obj2/shared/MaterialHandler.js @@ -1,4 +1,5 @@ /** + * @author Kai Salmen / https://kaisalmen.de * Development repository: https://github.com/kaisalmen/WWOBJLoader */ @@ -6,7 +7,8 @@ import { LineBasicMaterial, MaterialLoader, MeshStandardMaterial, - PointsMaterial + PointsMaterial, + VertexColors } from "../../../../../build/three.module.js"; @@ -63,7 +65,7 @@ MaterialHandler.prototype = { const defaultVertexColorMaterial = new MeshStandardMaterial( { color: 0xDCF1FF } ); defaultVertexColorMaterial.name = 'defaultVertexColorMaterial'; - defaultVertexColorMaterial.vertexColors = true; + defaultVertexColorMaterial.vertexColors = VertexColors; const defaultLineMaterial = new LineBasicMaterial(); defaultLineMaterial.name = 'defaultLineMaterial'; @@ -123,26 +125,21 @@ MaterialHandler.prototype = { } let materials = materialPayload.materials.serializedMaterials; - if ( materials !== undefined && materials !== null && Object.keys( materials ).length > 0 ) { const loader = new MaterialLoader(); let materialJson; - for ( materialName in materials ) { materialJson = materials[ materialName ]; - if ( materialJson !== undefined && materialJson !== null ) { material = loader.parse( materialJson ); - if ( this.logging.enabled ) { console.info( 'De-serialized material with name "' + materialName + '" will be added.' ); } - this.materials[ materialName ] = material; newMaterials[ materialName ] = material; @@ -151,7 +148,6 @@ MaterialHandler.prototype = { } } - materials = materialPayload.materials.runtimeMaterials; newMaterials = this.addMaterials( materials, true, newMaterials ); @@ -173,32 +169,27 @@ MaterialHandler.prototype = { newMaterials = {}; } - if ( materials !== undefined && materials !== null && Object.keys( materials ).length > 0 ) { let material; let existingMaterial; let add; - for ( const materialName in materials ) { material = materials[ materialName ]; add = overrideExisting === true; - if ( ! add ) { existingMaterial = this.materials[ materialName ]; add = ( existingMaterial === null || existingMaterial === undefined ); } - if ( add ) { this.materials[ materialName ] = material; newMaterials[ materialName ] = material; } - if ( this.logging.enabled && this.logging.debug ) { console.info( 'Material with name "' + materialName + '" was added.' ); @@ -214,7 +205,6 @@ MaterialHandler.prototype = { this.callbacks.onLoadMaterials( newMaterials ); } - return newMaterials; }, @@ -250,7 +240,6 @@ MaterialHandler.prototype = { const materialsJSON = {}; let material; - for ( const materialName in this.materials ) { material = this.materials[ materialName ]; diff --git a/examples/jsm/taskmanager/TaskManager.d.ts b/examples/jsm/taskmanager/TaskManager.d.ts index 788e4354e3d2f1..b5551fabb23b61 100644 --- a/examples/jsm/taskmanager/TaskManager.d.ts +++ b/examples/jsm/taskmanager/TaskManager.d.ts @@ -5,15 +5,17 @@ export class TaskManager { maxParallelExecutions: number; actualExecutionCount: number; storedExecutions: StoredExecution[]; + teardown: boolean; setVerbose(verbose: boolean): TaskManager; setMaxParallelExecutions(maxParallelExecutions: number): TaskManager; getMaxParallelExecutions(): number; supportsTaskType(taskType: string): boolean; - registerTaskType(taskType: string, initFunction: Function, executeFunction: Function, comRoutingFunction: Function, fallback: boolean, dependencyDescriptions?: any[]): TaskManager; - registerTaskTypeModule(taskType: string, workerModuleUrl: string): TaskManager; - initTaskType(taskType: string, config: object, transferables?: any): Promise; + registerTaskType(taskType: string, initFunction: Function, executeFunction: Function, comRoutingFunction: Function, fallback: boolean, dependencyDescriptions?: any[]): boolean; + registerTaskTypeModule(taskType: string, workerModuleUrl: string): boolean; + initTaskType(taskType: string, config: object, transferables?: any): Promise; + wait(milliseconds: any): Promise; enqueueForExecution(taskType: string, config: object, assetAvailableFunction: Function, transferables?: any): Promise; - _kickExecutions(): void; + _kickExecutions(): Promise; dispose(): TaskManager; } declare class WorkerTypeDefinition { @@ -21,19 +23,11 @@ declare class WorkerTypeDefinition { taskType: string; fallback: boolean; verbose: boolean; + initialised: boolean; functions: { - init: { - ref: Function; - code: string; - }; - execute: { - ref: Function; - code: string; - }; - comRouting: { - ref: Function; - code: string; - }; + init: Function; + execute: Function; + comRouting: Function; dependencies: { descriptions: any[]; code: string[]; @@ -45,16 +39,19 @@ declare class WorkerTypeDefinition { instances: TaskWorker[] | MockedTaskWorker[]; available: TaskWorker[] | MockedTaskWorker[]; }; + status: { + initStarted: boolean; + initComplete: boolean; + }; getTaskType(): string; setFunctions(initFunction: Function, executeFunction: Function, comRoutingFunction?: Function): void; setDependencyDescriptions(dependencyDescriptions: any[]): void; setWorkerModule(workerModuleUrl: string): void; isWorkerModule(): boolean; - loadDependencies(): Promise; - generateWorkerCode(dependencies: ArrayBuffer[]): Promise; - createWorkers(code: string): Promise; - createWorkerModules(): Promise; - initWorkers(instances: TaskWorker[] | MockedTaskWorker[], config: object, transferables: any): Promise; + loadDependencies(): () => []; + createWorkers(): Promise; + createWorkerModules(): Promise; + initWorkers(config: object, transferables: any): Promise; getAvailableTask(): TaskWorker | MockedTaskWorker | undefined; hasTask(): boolean; returnAvailableTask(taskWorker: TaskWorker | MockedTaskWorker): void; diff --git a/examples/jsm/taskmanager/TaskManager.js b/examples/jsm/taskmanager/TaskManager.js index ac2040991604b3..a1de986776e1a7 100644 --- a/examples/jsm/taskmanager/TaskManager.js +++ b/examples/jsm/taskmanager/TaskManager.js @@ -4,6 +4,7 @@ */ import { FileLoader } from "../../../build/three.module.js"; +import { TaskManagerDefaultRouting } from "./worker/tmDefaultComRouting.js"; /** * Register one to many tasks type to the TaskManager. Then init and enqueue a worker based execution by passing @@ -29,6 +30,8 @@ class TaskManager { * @type {StoredExecution[]} */ this.storedExecutions = []; + this.teardown = false; + this._kickExecutions().then( x => console.log( 'Teared down: ' + x ) ); } @@ -89,15 +92,20 @@ class TaskManager { * @param {function} comRoutingFunction The function that should handle communication, leave undefined for default behavior * @param {boolean} fallback Set to true if execution should be performed in main * @param {Object[]} [dependencyDescriptions] - * @return {TaskManager} + * @return {boolean} Tells if registration is possible (new=true) or if task was already registered (existing=false) */ registerTaskType ( taskType, initFunction, executeFunction, comRoutingFunction, fallback, dependencyDescriptions ) { - let workerTypeDefinition = new WorkerTypeDefinition( taskType, this.maxParallelExecutions, fallback, this.verbose ); - workerTypeDefinition.setFunctions( initFunction, executeFunction, comRoutingFunction ); - workerTypeDefinition.setDependencyDescriptions( dependencyDescriptions ); - this.taskTypes.set( taskType, workerTypeDefinition ); - return this; + let allowedToRegister = ! this.supportsTaskType( taskType ); + if ( allowedToRegister ) { + + let workerTypeDefinition = new WorkerTypeDefinition( taskType, this.maxParallelExecutions, fallback, this.verbose ); + workerTypeDefinition.setFunctions( initFunction, executeFunction, comRoutingFunction ); + workerTypeDefinition.setDependencyDescriptions( dependencyDescriptions ); + this.taskTypes.set( taskType, workerTypeDefinition ); + + } + return allowedToRegister; } @@ -106,14 +114,19 @@ class TaskManager { * * @param {string} taskType The name to be used for registration. * @param {string} workerModuleUrl The URL to be used for the Worker. Module must provide logic to handle "init" and "execute" messages. - * @return {TaskManager} + * @return {boolean} Tells if registration is possible (new=true) or if task was already registered (existing=false) */ registerTaskTypeModule ( taskType, workerModuleUrl ) { - let workerTypeDefinition = new WorkerTypeDefinition( taskType, this.maxParallelExecutions, false, this.verbose ); - workerTypeDefinition.setWorkerModule( workerModuleUrl ); - this.taskTypes.set( taskType, workerTypeDefinition ); - return this; + let allowedToRegister = ! this.supportsTaskType( taskType ); + if ( allowedToRegister ) { + + let workerTypeDefinition = new WorkerTypeDefinition( taskType, this.maxParallelExecutions, false, this.verbose ); + workerTypeDefinition.setWorkerModule( workerModuleUrl ); + this.taskTypes.set( taskType, workerTypeDefinition ); + + } + return allowedToRegister; } @@ -127,21 +140,51 @@ class TaskManager { async initTaskType ( taskType, config, transferables ) { let workerTypeDefinition = this.taskTypes.get( taskType ); - if ( workerTypeDefinition.isWorkerModule() ) { + if ( workerTypeDefinition ) { - return await workerTypeDefinition.createWorkerModules() - .then( instances => workerTypeDefinition.initWorkers( instances, config, transferables ) ); + if ( ! workerTypeDefinition.status.initStarted ) { - } - else { + workerTypeDefinition.status.initStarted = true; + if ( workerTypeDefinition.isWorkerModule() ) { + + await workerTypeDefinition.createWorkerModules() + .then( instances => workerTypeDefinition.initWorkers( config, transferables ) ) + .then( workerTypeDefinition.status.initComplete ) + .catch( x => console.error( x ) ); + + } else { + + await workerTypeDefinition.loadDependencies() + .then( code => workerTypeDefinition.createWorkers() ) + .then( instances => workerTypeDefinition.initWorkers( config, transferables ) ) + .then( workerTypeDefinition.status.initComplete ) + .catch( x => console.error( x ) ); + + } + + } + else { + + while ( ! workerTypeDefinition.status.initComplete ) { - return await workerTypeDefinition.loadDependencies() - .then( buffers => workerTypeDefinition.generateWorkerCode( buffers ) ) - .then( code => workerTypeDefinition.createWorkers( code ) ) - .then( instances => workerTypeDefinition.initWorkers( instances, config, transferables ) ) - .catch( x => console.error( x ) ); + await this.wait( 10 ); + + } + + } } + + } + + async wait ( milliseconds ) { + + return new Promise(resolve => { + + setTimeout( resolve, milliseconds ); + + } ); + } /** @@ -160,77 +203,86 @@ class TaskManager { this.storedExecutions.push( new StoredExecution( taskType, config, assetAvailableFunction, resolveUser, rejectUser, transferables ) ); } ); - this._kickExecutions(); return localPromise; } - _kickExecutions () { + async _kickExecutions () { - while ( this.actualExecutionCount < this.maxParallelExecutions && this.storedExecutions.length > 0 ) { + while ( ! this.teardown ) { - let storedExecution = this.storedExecutions.shift(); - if ( storedExecution ) { + let counter = 0; + while ( this.storedExecutions.length > 0 ) { - let workerTypeDefinition = this.taskTypes.get( storedExecution.taskType ); - if ( workerTypeDefinition.hasTask() ) { + if ( this.actualExecutionCount < this.maxParallelExecutions && counter < this.storedExecutions.length ) { + // TODO: storedExecutions and results from worker seem to get mixed up + let storedExecution = this.storedExecutions[ counter ]; + let workerTypeDefinition = this.taskTypes.get( storedExecution.taskType ); let taskWorker = workerTypeDefinition.getAvailableTask(); - this.actualExecutionCount++; - let promiseWorker = new Promise( ( resolveWorker, rejectWorker ) => { + if ( taskWorker ) { + + this.storedExecutions.splice( counter, 1 ); + this.actualExecutionCount ++; + let promiseWorker = new Promise( ( resolveWorker, rejectWorker ) => { + + taskWorker.onmessage = function ( e ) { + + // allow intermediate asset provision before flagging execComplete + if ( e.data.cmd === 'assetAvailable' ) { - taskWorker.onmessage = function ( e ) { + if ( storedExecution.assetAvailableFunction instanceof Function ) { - // allow intermediate asset provision before flagging execComplete - if ( e.data.cmd === 'assetAvailable' ) { + storedExecution.assetAvailableFunction( e.data ); - if ( storedExecution.assetAvailableFunction instanceof Function ) { + } - storedExecution.assetAvailableFunction( e.data ); + } else { + + resolveWorker( e ); } - } - else { + }; + taskWorker.onerror = rejectWorker; - resolveWorker( e ); + taskWorker.postMessage( { + cmd: "execute", + workerId: taskWorker.getId(), + config: storedExecution.config + }, storedExecution.transferables ); - } + } ); + promiseWorker.then( ( e ) => { - }; - taskWorker.onerror = rejectWorker; + workerTypeDefinition.returnAvailableTask( taskWorker ); + storedExecution.resolve( e.data ); + this.actualExecutionCount --; - taskWorker.postMessage( { - cmd: "execute", - workerId: taskWorker.getId(), - config: storedExecution.config - }, storedExecution.transferables ); + } ).catch( ( e ) => { - } ); - promiseWorker.then( ( e ) => { + storedExecution.reject( "Execution error: " + e ); - workerTypeDefinition.returnAvailableTask( taskWorker ); - storedExecution.resolve( e.data ); - this.actualExecutionCount --; - this._kickExecutions(); + } ); - } ).catch( ( e ) => { + } else { - storedExecution.reject( "Execution error: " + e ); + counter ++; - } ); + } - } - else { + } else { - // try later again, add at the end for now - this.storedExecutions.push( storedExecution ); + counter = 0; + await this.wait( 1 ); } } + await this.wait( 1 ); } + } /** @@ -239,6 +291,7 @@ class TaskManager { */ dispose () { + this.teardown = true; for ( let workerTypeDefinition of this.taskTypes.values() ) { workerTypeDefinition.dispose(); @@ -267,25 +320,14 @@ class WorkerTypeDefinition { this.taskType = taskType; this.fallback = fallback; this.verbose = verbose === true; + this.initialised = false; this.functions = { - init: { - /** @type {function} */ - ref: null, - /** @type {string} */ - code: null - }, - execute: { - /** @type {function} */ - ref: null, - /** @type {string} */ - code: null - }, - comRouting: { - /** @type {function} */ - ref: null, - /** @type {string} */ - code: null - }, + /** @type {function} */ + init: null, + /** @type {function} */ + execute: null, + /** @type {function} */ + comRouting: null, dependencies: { /** @type {Object[]} */ descriptions: [], @@ -308,6 +350,11 @@ class WorkerTypeDefinition { available: [] }; + this.status = { + initStarted: false, + initComplete: false + } + } getTaskType () { @@ -318,6 +365,7 @@ class WorkerTypeDefinition { /** * Set the three functions. A default comRouting function is used if it is not passed here. + * Then it creates the code fr. * * @param {function} initFunction The function to be called when the worker is initialised * @param {function} executeFunction The function to be called when the worker is executed @@ -325,29 +373,19 @@ class WorkerTypeDefinition { */ setFunctions ( initFunction, executeFunction, comRoutingFunction ) { - this.functions.init.ref = initFunction; - this.functions.execute.ref = executeFunction; - this.functions.comRouting.ref = comRoutingFunction; - - if ( this.fallback && this.functions.comRouting.ref === undefined || this.functions.comRouting.ref === null ) { - - let comRouting = function ( message, init, execute ) { - - let payload = message.data; - if ( payload.cmd === 'init' ) { - - init( self, payload.id, payload.config ); - - } else if ( payload.cmd === 'execute' ) { + this.functions.init = initFunction; + this.functions.execute = executeFunction; + this.functions.comRouting = comRoutingFunction; + if ( this.functions.comRouting === undefined || this.functions.comRouting === null ) { - execute( self, payload.id, payload.config ); - - } - - } - this.functions.comRouting.ref = comRouting; + this.functions.comRouting = TaskManagerDefaultRouting.comRouting; } + this.workers.code.push( 'const init = ' + this.functions.init.toString() + ';\n\n' ); + this.workers.code.push( 'const execute = ' + this.functions.execute.toString() + ';\n\n' ); + this.workers.code.push( 'const comRouting = ' + this.functions.comRouting.toString() + ';\n\n' ); + this.workers.code.push( 'self.addEventListener( "message", message => comRouting( self, message, null, init, execute ), false );' ); + } /** @@ -390,65 +428,38 @@ class WorkerTypeDefinition { /** * Loads all dependencies and stores each as {@link ArrayBuffer} into the array. Returns if all loading is completed. * - * @return {Promise} + * @return {} */ async loadDependencies () { + let promises = []; let fileLoader = new FileLoader(); fileLoader.setResponseType( 'arraybuffer' ); for ( let description of this.functions.dependencies.descriptions ) { - let dep; if ( description.url ) { let url = new URL( description.url, window.location.href ); - dep = await fileLoader.loadAsync( url.href, report => { if ( this.verbose ) console.log( report ); } ) + promises.push( fileLoader.loadAsync( url.href, report => { if ( this.verbose ) console.log( report ); } ) ); } if ( description.code ) { - dep = description.code; + promises.push( new Promise( resolve => resolve( description.code ) ) ); } - this.functions.dependencies.code.push( dep ); } if ( this.verbose ) console.log( 'Task: ' + this.getTaskType() + ': Waiting for completion of loading of all dependencies.'); - return await Promise.all( this.functions.dependencies.code ); - - } - - /** - * Uses the configured values for init, execute and comRouting and embeds it in necessary glue code. - * - * @param {ArrayBuffer[]} dependencies - * @return {Promise} - */ - async generateWorkerCode ( dependencies ) { - - this.functions.init.code = 'const init = ' + this.functions.init.ref.toString() + ';\n\n'; - this.functions.execute.code = 'const execute = ' + this.functions.execute.ref.toString() + ';\n\n'; - if ( this.functions.comRouting.ref !== null ) { - - this.functions.comRouting.code = "const comRouting = " + this.functions.comRouting.ref.toString() + ";\n\n"; - - } - this.workers.code.push( this.functions.init.code ); - this.workers.code.push( this.functions.execute.code ); - this.workers.code.push( this.functions.comRouting.code ); - this.workers.code.push( 'self.addEventListener( "message", message => comRouting( message, init, execute ), false );' ); - - return this.workers.code; + this.functions.dependencies.code = await Promise.all( promises ); } /** * Creates workers based on the configured function and dependency strings. * - * @param {string} code - * @return {Promise} */ - async createWorkers ( code ) { + async createWorkers () { let worker; if ( !this.fallback ) { @@ -467,20 +478,18 @@ class WorkerTypeDefinition { for ( let i = 0; i < this.workers.instances.length; i ++ ) { - worker = new MockedTaskWorker( i, this.functions.init.ref, this.functions.execute.ref ); + worker = new MockedTaskWorker( i, this.functions.init, this.functions.execute ); this.workers.instances[ i ] = worker; } } - return this.workers.instances; } /** * Creates module workers. * - * @return {Promise} */ async createWorkerModules () { @@ -490,23 +499,21 @@ class WorkerTypeDefinition { this.workers.instances[ i ] = worker; } - return this.workers.instances; } /** * Initialises all workers with common configuration data. * - * @param {TaskWorker[]|MockedTaskWorker[]} instances * @param {object} config * @param {Object} transferables - * @return {Promise} */ - async initWorkers ( instances, config, transferables ) { + async initWorkers ( config, transferables ) { - for ( let taskWorker of instances ) { + let promises = []; + for ( let taskWorker of this.workers.instances ) { - await new Promise( ( resolveWorker, rejectWorker ) => { + let taskWorkerPromise = new Promise( ( resolveWorker, rejectWorker ) => { taskWorker.onmessage = resolveWorker; taskWorker.onerror = rejectWorker; @@ -527,11 +534,12 @@ class WorkerTypeDefinition { }, transferablesToWorker ); } ); - this.workers.available.push( taskWorker ); + promises.push( taskWorkerPromise ); } if ( this.verbose ) console.log( 'Task: ' + this.getTaskType() + ': Waiting for completion of initialization of all workers.'); - return await Promise.all( this.workers.available ); + await Promise.all( promises ); + this.workers.available = this.workers.instances; } @@ -542,7 +550,13 @@ class WorkerTypeDefinition { */ getAvailableTask () { - return this.workers.available.shift(); + let task = undefined; + if ( this.hasTask() ) { + + task = this.workers.available.shift(); + + } + return task; } @@ -682,26 +696,12 @@ class MockedTaskWorker { postMessage( message, transfer ) { let scope = this; - let comRouting = function ( message ) { - let self = { - postMessage: function ( m ) { - scope.onmessage( { data: m } ) - }, + let self = { + postMessage: function ( m ) { + scope.onmessage( { data: m } ) } - - let payload = message.data; - if ( payload.cmd === 'init' ) { - - scope.functions.init( self, payload.id, payload.config ); - - } - else if ( payload.cmd === 'execute' ) { - - scope.functions.execute( self, payload.id, payload.config ); - - } - }; - comRouting( { data: message } ) + } + TaskManagerDefaultRouting.comRouting( self, { data: message }, null, scope.functions.init, scope.functions.execute ) } diff --git a/examples/jsm/taskmanager/worker/tmOBJLoader2.js b/examples/jsm/taskmanager/worker/tmOBJLoader2.js index f63fe135805084..643d2d5404f16a 100644 --- a/examples/jsm/taskmanager/worker/tmOBJLoader2.js +++ b/examples/jsm/taskmanager/worker/tmOBJLoader2.js @@ -38,6 +38,9 @@ const OBJ2LoaderWorker = { ObjectManipulator.applyProperties( objParser, payload.config, false ); ObjectManipulator.applyProperties( objParser, callbacks, false ); */ + context.obj2.objParser._init(); + + if ( config.buffer !== undefined && config.buffer !== null ) context.obj2.buffer = config.buffer; context.obj2.objParser.objectId = config.id; diff --git a/examples/webgl_loader_obj2_options.html b/examples/webgl_loader_obj2_options.html index 905fcdd6d36e3b..7ed293013158ef 100644 --- a/examples/webgl_loader_obj2_options.html +++ b/examples/webgl_loader_obj2_options.html @@ -93,7 +93,7 @@ this.cube = null; this.pivot = null; - this.taskManager = new TaskManager( 2 ); + this.taskManager = new TaskManager( 1 ); }; WWOBJLoader2Example.prototype = { @@ -192,7 +192,7 @@ }; let objLoader2Parallel = new OBJLoader2Parallel() -// .setTaskManager( this.taskManager ) + .setTaskManager( this.taskManager ) .setModelName( modelName ) .setJsmWorker( this.useJsmWorker, new URL( OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH, window.location.href ) ) .setCallbackOnLoad( callbackOnLoad ) @@ -249,7 +249,7 @@ this.pivot.add( local ); let objLoader2Parallel = new OBJLoader2Parallel() -// .setTaskManager( this.taskManager ) + .setTaskManager( this.taskManager ) .setModelName( modelName ) .setJsmWorker( this.useJsmWorker, new URL( OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH, window.location.href ) ); @@ -277,7 +277,7 @@ this.pivot.add( local ); let objLoader2Parallel = new OBJLoader2Parallel() -// .setTaskManager( this.taskManager ) + .setTaskManager( this.taskManager ) .setModelName( local.name ) .setExecuteParallel( false ); @@ -298,7 +298,7 @@ this.pivot.add( local ); let objLoader2Parallel = new OBJLoader2Parallel() -// .setTaskManager( this.taskManager ) + .setTaskManager( this.taskManager ) .setModelName( local.name ) .setJsmWorker( this.useJsmWorker, new URL( OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH, window.location.href ) ) .setBaseObject3d( local ); diff --git a/examples/webgl_loader_taskmanager.html b/examples/webgl_loader_taskmanager.html index 23c5288438ad46..659eb8ca3b697c 100644 --- a/examples/webgl_loader_taskmanager.html +++ b/examples/webgl_loader_taskmanager.html @@ -266,7 +266,7 @@ } if ( awaiting.length > 0 ) { - return Promise.all( awaiting ); + return await Promise.all( awaiting ); } else { @@ -348,6 +348,7 @@ case 'material': this.materialHandler.addPayloadMaterials( payload ); + break; case 'void': break;