diff --git a/examples/jsm/loaders/TaskManager.js b/examples/jsm/loaders/TaskManager.js index 769615304d3f5d..0e1d8089ef3af1 100644 --- a/examples/jsm/loaders/TaskManager.js +++ b/examples/jsm/loaders/TaskManager.js @@ -5,6 +5,177 @@ import { FileLoaderBufferAsync } from "./obj2/utils/FileLoaderBufferAsync.js"; +/** + * + */ +class TaskManager { + + constructor () { + + this.types = new Map(); + + } + + /** + * Returns true if support for the given task type is available. + * @param {string} type The type as string + * @return boolean + */ + supportsType ( type ) { + + return this.types.has( type ); + + } + + /** + * Registers functionality for a new task type. + * @param {string} type + * @param {number} maximumWorkerCount + * @param {function} initFunction + * @param {function} executeFunction + * @param {function} comRoutingFunction + * @param {String[]} [dependencyUrls] + * @return {TaskManager} + */ + registerType ( type, maximumWorkerCount, initFunction, executeFunction, comRoutingFunction, dependencyUrls ) { + + let workerTypeDefinition = new WorkerTypeDefinition( type, maximumWorkerCount ); + workerTypeDefinition.setFunctions( initFunction, executeFunction, comRoutingFunction ); + workerTypeDefinition.setDependencyUrls( dependencyUrls ); + this.types.set( type, workerTypeDefinition ); + return this; + + } + + /** + * Registers functionality for a new task type based on module file. + * @param {string} type + * @param {number} maximumWorkerCount + * @param {string} workerJsmUrl + * @return {TaskManager} + */ + registerTypeJsm ( type, maximumWorkerCount, workerJsmUrl ) { + + let workerTypeDefinition = new WorkerTypeDefinition( type, maximumWorkerCount ); + workerTypeDefinition.setWorkerJsm( workerJsmUrl ); + this.types.set( type, workerTypeDefinition ); + return this; + + } + + /** + * Provides initialization configuration and dependencies for all tasks of given type. + * @param {string} type + * @param {object} config + * @param {Transferable[]} [transferables] + */ + async initType ( type, config, transferables ) { + + let workerTypeDefinition = this.types.get( type ); + if ( workerTypeDefinition.isWorkerJsm() ) { + + return await workerTypeDefinition.createWorkersJsm() + .then( instances => workerTypeDefinition.initWorkers( instances, config, transferables ) ); + + } + else { + + 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 ) ); + + } + } + + /** + * Queues a new task of the given type. Task will not execute until initialization completes. + * @param {string} type + * @param {number} cost + * @param {object} config + * @param {Transferable[]} [transferables] + * @return {Promise} + */ + async addTask ( type, cost, config, transferables ) { + + let workerTypeDefinition = this.types.get( type ); + let taskWorker = workerTypeDefinition.getAvailableTask(); + + return new Promise( ( resolveUser, rejectUser ) => { + + /** + * Function wrapping worker execution. It binds resolve and reject to onmessage and onerror. + * + * @param {TaskWorker} taskWorkerExecute + * @param {function} resolveExecute + * @param {function} rejectExecute + */ + function executeWorker( taskWorkerExecute, resolveExecute, rejectExecute ) { + + let promiseWorker = new Promise( ( resolveWorker, rejectWorker ) => { + + taskWorkerExecute.onmessage = resolveWorker; + taskWorkerExecute.onerror = rejectWorker; + + taskWorkerExecute.postMessage( { + cmd: "execute", + id: taskWorkerExecute.getId(), + config: config + }, transferables ); + + } ); + promiseWorker.then( ( e ) => { + + resolveExecute( e.data ); + workerTypeDefinition.returnAvailableTask( taskWorkerExecute ); + + } ).catch( ( e ) => { + + rejectExecute( "Execution error: " + e ); + + } ); + + } + + if ( taskWorker ) { + + executeWorker( taskWorker, resolveUser, rejectUser ); + + } + else { + + // store promises that can not directly executed as the limit has been reached. + // storedPromises are checked when returnAvailableTask is called. + workerTypeDefinition.workers.storedPromises.push( { + exec: executeWorker, + resolve: resolveUser, + reject: rejectUser + } ); + + } + + } ) + + } + + /** + * Destroys all workers and associated resources. + * @return {TaskManager} + */ + dispose () { + + for ( let workerTypeDefinition of this.types.values() ) { + + workerTypeDefinition.dispose(); + + } + return this; + + } + +} + /** * Defines a worker type: functions, dependencies and runtime information once it was created. */ @@ -15,7 +186,8 @@ class WorkerTypeDefinition { * * @param {Number} maximumCount */ - constructor ( maximumCount ) { + constructor ( type, maximumCount ) { + this.type = type; this.functions = { init: { ref: null, @@ -25,7 +197,7 @@ class WorkerTypeDefinition { ref: null, code: null }, - comRouter: { + comRouting: { ref: null, code: null } @@ -40,26 +212,52 @@ class WorkerTypeDefinition { this.workerJsmUrl = null; this.workers = { maximumCount: maximumCount, + dependencies: [], code: [], - instances: new Set(), + instances: [], available: [], storedPromises: [] }; } + getType () { + + return this.type; + + } + /** * * @param {function} initFunction * @param {function} executeFunction - * @param {function} comRouterFunction + * @param {function} [comRoutingFunction] */ - setFunctions ( initFunction, executeFunction, comRouterFunction ) { + setFunctions ( initFunction, executeFunction, comRoutingFunction ) { this.functions.init.ref = initFunction; this.functions.execute.ref = executeFunction; - this.functions.comRouter.ref = comRouterFunction; + this.functions.comRouting.ref = comRoutingFunction; + + if ( this.workers.maximumCount > 0 && 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' ) { + + execute( self, payload.id, payload.config ); + } + + } + this.functions.comRouting.ref = comRouting; + + } } /** @@ -69,7 +267,7 @@ class WorkerTypeDefinition { */ setDependencyUrls ( dependencyUrls ) { - dependencyUrls.forEach( url => { this.dependencyUrls.add( new URL( url, window.location.href ) ) } ); + if ( dependencyUrls ) dependencyUrls.forEach( url => { this.dependencyUrls.add( new URL( url, window.location.href ) ) } ); } @@ -102,37 +300,35 @@ class WorkerTypeDefinition { async loadDependencies () { let fileLoaderBufferAsync = new FileLoaderBufferAsync(); - let buffers = []; for ( let url of this.dependencyUrls.entries() ) { - buffers.push( fileLoaderBufferAsync.loadFileAsync( url[ 1 ], ( report => console.log( report.detail.text ) ) ) ); + let dep = await fileLoaderBufferAsync.loadFileAsync( url[ 1 ], ( report => console.log( report.detail.text ) ) ) + this.workers.dependencies.push( dep ); } - console.log( 'Waiting for completion of loading of all assets!'); - return await Promise.all( buffers ); + console.log( 'Task: ' + this.getType() + ': Waiting for completion of loading of all dependencies.'); + return await Promise.all( this.workers.dependencies ); } /** * - * @param {ArrayBuffer[]} buffers + * @param {ArrayBuffer[]} dependencies * @return {Promise} */ - async generateWorkerCode ( buffers ) { + 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.comRouter.ref !== null ) { + if ( this.functions.comRouting.ref !== null ) { - this.functions.comRouter.code = "const comRouter = " + this.functions.comRouter.ref.toString() + ";\n\n"; + this.functions.comRouting.code = "const comRouting = " + this.functions.comRouting.ref.toString() + ";\n\n"; } - buffers.forEach( buffer => this.workers.code.push( buffer ) ); - this.workers.code.push( this.functions.init.code ); this.workers.code.push( this.functions.execute.code ); - this.workers.code.push( this.functions.comRouter.code ); - this.workers.code.push( 'self.addEventListener( "message", comRouter, false );' ); + 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; @@ -141,19 +337,22 @@ class WorkerTypeDefinition { /** * * @param {string} code - * @return {Promise>} + * @return {Promise} */ async createWorkers ( code ) { - for ( let worker, i = 0; i < this.workers.maximumCount; i++ ) { + let worker, workerBlob; + for ( let i = 0; i < this.workers.maximumCount; i++ ) { - let workerBlob = new Blob( code, { type: 'application/javascript' } ); - worker = new Worker( window.URL.createObjectURL( workerBlob ) ); - // TODO: why is this not a map with int index? - this.workers.instances.add( { - worker: worker, - id: i - } ); + workerBlob = new Blob( this.workers.dependencies.concat( this.workers.code ), { type: 'application/javascript' } ); + worker = new TaskWorker( i, window.URL.createObjectURL( workerBlob ) ); + this.workers.instances[ i ] = worker; + + } + if ( this.workers.instances.length === 0) { + + worker = new FakeTaskWorker( 0, this.functions.init.ref, this.functions.execute.ref ); + this.workers.instances[ 0 ] = worker; } return this.workers.instances; @@ -162,17 +361,14 @@ class WorkerTypeDefinition { /** * - * @return {Promise>} + * @return {Promise} */ async createWorkersJsm () { for ( let worker, i = 0; i < this.workers.maximumCount; i++ ) { - worker = new Worker( this.workerJsmUrl.href, { type: "module" } ); - this.workers.instances.add( { - worker: worker, - id: i - } ); + worker = new TaskWorker( i, this.workerJsmUrl.href, { type: "module" } ); + this.workers.instances[ i ] = worker; } return this.workers.instances; @@ -181,32 +377,39 @@ class WorkerTypeDefinition { /** * - * @param {object} instances + * @param {TaskWorker[]} instances * @param {object} config * @param {Transferable[]} transferables - * @return {Promise<[]>} + * @return {Promise} */ async initWorkers ( instances, config, transferables ) { - let it = instances.values(); - for ( let workerObj; workerObj = it.next().value; ) { + for ( let taskWorker of instances ) { + + await new Promise( ( resolveWorker, rejectWorker ) => { - workerObj.worker.postMessage( { - cmd: "init", - id: workerObj.id, - config: config - }, transferables ); - this.workers.available.push( workerObj ); + taskWorker.onmessage = resolveWorker; + taskWorker.onerror = rejectWorker; + + taskWorker.postMessage( { + cmd: "init", + id: taskWorker.getId(), + config: config + }, transferables ); + + } ); + this.workers.available.push( taskWorker ); } - return this.workers.available; + console.log( 'Task: ' + this.getType() + ': Waiting for completion of initialization of all workers.'); + return await Promise.all( this.workers.available ); } /** - * Returns a Worker or none. + * Returns the first {@link TaskWorker} from array of available workers. * - * @return {Worker|null} + * @return {TaskWorker|null} */ getAvailableTask () { @@ -216,15 +419,16 @@ class WorkerTypeDefinition { /** * - * @param {object} workerObj + * @param {TaskWorker} taskWorker */ - returnAvailableTask ( workerObj ) { + returnAvailableTask ( taskWorker ) { - this.workers.available.push( workerObj ); + this.workers.available.push( taskWorker ); let storedExec = this.workers.storedPromises.shift(); if ( storedExec ) { storedExec.exec( this.getAvailableTask(), storedExec.resolve, storedExec.reject ); + } } @@ -234,176 +438,98 @@ class WorkerTypeDefinition { */ dispose () { - let it = this.workers.instances.values(); - for ( let workerObj; workerObj = it.next().value; ) { + for ( let taskWorker of this.workers.instances ) { - workerObj.worker.terminate(); + taskWorker.terminate(); } + } } - /** * */ -class TaskManager { - - constructor () { - - this.types = new Map(); - - } +class TaskWorker extends Worker { /** - * Returns true if support for the given task type is available. - * @param {string} type The type as string - * @return boolean + * + * @param id + * @param aURL + * @param options */ - supportsType ( type ) { + constructor( id, aURL, options ) { - return this.types.has( type ); + super( aURL, options ); + this.id = id; } /** - * Registers functionality for a new task type. - * @param {string} type - * @param {number} maximumWorkerCount - * @param {function} initFunction - * @param {function} executeFunction - * @param {function} comRouterFunction - * @param {String[]} [dependencyUrls] - * @return {TaskManager} + * + * @return {*} */ - registerType ( type, maximumWorkerCount, initFunction, executeFunction, comRouterFunction, dependencyUrls ) { + getId() { - let workerTypeDefinition = new WorkerTypeDefinition( maximumWorkerCount ); - workerTypeDefinition.setFunctions( initFunction, executeFunction, comRouterFunction ); - workerTypeDefinition.setDependencyUrls( dependencyUrls ); - this.types.set( type, workerTypeDefinition ); - return this; + return this.id; } - /** - * Registers functionality for a new task type based on module file. - * @param {string} type - * @param {number} maximumWorkerCount - * @param {string} workerJsmUrl - * @return {TaskManager} - */ - registerTypeJsm ( type, maximumWorkerCount, workerJsmUrl ) { - - let workerTypeDefinition = new WorkerTypeDefinition( maximumWorkerCount ); - workerTypeDefinition.setWorkerJsm( workerJsmUrl ); - this.types.set( type, workerTypeDefinition ); - return this; +} - } +/** + * + */ +class FakeTaskWorker extends TaskWorker { /** - * Provides initialization configuration and dependencies for all tasks of given type. - * @param {string} type - * @param {object} config - * @param {Transferable[]} [transferables] + * + * @param id + * @param {function} initFunction + * @param {function} executeFunction */ - async initType ( type, config, transferables ) { - - let workerTypeDefinition = this.types.get( type ); - if ( workerTypeDefinition.isWorkerJsm() ) { - - return await workerTypeDefinition.createWorkersJsm() - .then( instances => workerTypeDefinition.initWorkers( instances, config, transferables ) ); + constructor( id, initFunction, executeFunction ) { + super( id, null ) + this.functions = { + init: initFunction, + execute: executeFunction } - else { - 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 ) ); - - } } /** - * Queues a new task of the given type. Task will not execute until initialization completes. - * @param {string} type - * @param {number} cost - * @param {object} config - * @param {Transferable[]} [transferables] - * @return {Promise} + * + * @param message */ - async addTask ( type, cost, config, transferables ) { - - let workerTypeDefinition = this.types.get( type ); - let workerObj = workerTypeDefinition.getAvailableTask(); - - return new Promise( ( resolveUser, rejectUser ) => { - - function executeWorker( workerObjExecute, resolveExecute, rejectExecute ) { - - let promiseWorker = new Promise( ( resolveWorker, rejectWorker ) => { - - workerObjExecute.worker.onmessage = resolveWorker; - workerObjExecute.worker.onerror = rejectWorker; - - workerObjExecute.worker.postMessage( { - cmd: "execute", - id: workerObjExecute.id, - config: config - }, transferables ); - - } ); - promiseWorker.then( ( e ) => { - - resolveExecute( e.data ); - workerTypeDefinition.returnAvailableTask( workerObjExecute ); - - } ).catch( ( e ) => { - - rejectExecute( "Execution error: " + e ); - - } ); - + postMessage( message ) { + + let scope = this; + let comRouting = function ( message ) { + let self = { + postMessage: function ( m ) { + scope.onmessage( { data: m } ) + }, } - if ( workerObj ) { + let payload = message.data; + if ( payload.cmd === 'init' ) { - executeWorker( workerObj, resolveUser, rejectUser ); + scope.functions.init( self, payload.id, payload.config ); } - else { + else if ( payload.cmd === 'execute' ) { - workerTypeDefinition.workers.storedPromises.push( { - exec: executeWorker, - resolve: resolveUser, - reject: rejectUser - } ); + scope.functions.execute( self, payload.id, payload.config ); } - } ) - - } - - /** - * Destroys all workers and associated resources. - * @return {TaskManager} - */ - dispose () { - - for ( let workerTypeDefinition of this.types.values() ) { - - workerTypeDefinition.dispose(); - - } - return this; + }; + comRouting( { data: message } ) } } + export { TaskManager }; diff --git a/examples/jsm/loaders/obj2/utils/FileLoaderBufferAsync.js b/examples/jsm/loaders/obj2/utils/FileLoaderBufferAsync.js index a7a72269831c46..64bdd662035e87 100644 --- a/examples/jsm/loaders/obj2/utils/FileLoaderBufferAsync.js +++ b/examples/jsm/loaders/obj2/utils/FileLoaderBufferAsync.js @@ -23,7 +23,7 @@ class FileLoaderBufferAsync extends FileLoader { * * @param {URL} url * @param {Function} [onProgress] - * @return {Promise} + * @return {Promise} */ loadFileAsync ( url, onProgress ) { let numericalValueRef = 0; diff --git a/examples/jsm/taskmanager/tmDefaultComRouting.js b/examples/jsm/taskmanager/tmDefaultComRouting.js new file mode 100644 index 00000000000000..8baa758d173261 --- /dev/null +++ b/examples/jsm/taskmanager/tmDefaultComRouting.js @@ -0,0 +1,19 @@ +/** + * @author Kai Salmen / www.kaisalmen.de + */ + +function comRouting ( message, init, execute ) { + let payload = message.data; + if ( payload.cmd === 'init' ) { + + init( self, payload.id, payload.config ); + + } + else if ( payload.cmd === 'execute' ) { + + execute( self, payload.id, payload.config ); + + } +} + +export { comRouting } \ No newline at end of file diff --git a/examples/jsm/taskmanager/tmJsmExample.js b/examples/jsm/taskmanager/tmJsmExample.js index bdb1cbe5ffad28..02c63b03462be1 100644 --- a/examples/jsm/taskmanager/tmJsmExample.js +++ b/examples/jsm/taskmanager/tmJsmExample.js @@ -8,20 +8,22 @@ import { import { TransferableUtils } from "../loaders/obj2/utils/TransferableUtils.js"; +import { comRouting } from "./tmDefaultComRouting.js"; -function init ( id, config ) { - self.storage = { + +function init ( context, id, config ) { + context.storage = { whoami: id, }; - self.postMessage( { + context.postMessage( { cmd: "init", id: id } ); } -async function execute ( id, config ) { +function execute ( context, id, config ) { let bufferGeometry = new TorusKnotBufferGeometry( 20, 3, 100, 64 ); @@ -35,28 +37,14 @@ async function execute ( id, config ) { let payload = TransferableUtils.packageBufferGeometry( bufferGeometry, 'tmProto' + config.count, 2,[ 'defaultPointMaterial' ] ); let randArray = new Uint8Array( 3 ); - self.crypto.getRandomValues( randArray ); + context.crypto.getRandomValues( randArray ); payload.main.params.color = { r: randArray[ 0 ] / 255, g: randArray[ 1 ] / 255, b: randArray[ 2 ] / 255 }; - payload.postMessage( self ); - -} - -function manageCom ( message ) { - let payload = message.data; - if ( payload.cmd === 'init' ) { - - init( payload.id, payload.config ); + payload.postMessage( context ); - } - else if ( payload.cmd === 'execute' ) { - - execute( payload.id, payload.config ); - - } } -self.addEventListener( 'message', manageCom, false ); +self.addEventListener( 'message', message => comRouting( message, init, execute ), false ); diff --git a/examples/jsm/taskmanager/tmJsmExampleNoThree.js b/examples/jsm/taskmanager/tmJsmExampleNoThree.js index 4146cd373b828f..4a50f5e22297e6 100644 --- a/examples/jsm/taskmanager/tmJsmExampleNoThree.js +++ b/examples/jsm/taskmanager/tmJsmExampleNoThree.js @@ -5,23 +5,22 @@ import { MeshMessageStructure } from "../loaders/obj2/utils/TransferableUtils.js"; +import { comRouting } from "./tmDefaultComRouting.js"; -self.config = {}; +function init ( context, id, config ) { -function init ( id, config ) { - - self.config = config; - self.postMessage( { + context.config = config; + context.postMessage( { cmd: "init", id: id } ); } -function execute ( id, config ) { +function execute ( context, id, config ) { - let payload = MeshMessageStructure.cloneMessageStructure( self.config ); + let payload = MeshMessageStructure.cloneMessageStructure( context.config ); let vertexArray = payload.main.buffers.vertices.buffer; for ( let i = 0; i < vertexArray.length; i++ ) { @@ -32,28 +31,14 @@ function execute ( id, config ) { payload.main.params.geometryType = 1; payload.main.materials.materialNames = [ 'defaultLineMaterial' ]; let randArray = new Uint8Array( 3 ); - self.crypto.getRandomValues( randArray ); + context.crypto.getRandomValues( randArray ); payload.main.params.color = { r: randArray[ 0 ] / 255, g: randArray[ 1 ] / 255, b: randArray[ 2 ] / 255 }; - payload.postMessage( self ); - -} - -function manageCom ( message ) { - let payload = message.data; - if ( payload.cmd === 'init' ) { - - init( payload.id, payload.config ); + payload.postMessage( context ); - } - else if ( payload.cmd === 'execute' ) { - - execute( payload.id, payload.config ); - - } } -self.addEventListener( 'message', manageCom, false ); +self.addEventListener( 'message', message => comRouting( message, init, execute ), false ); diff --git a/examples/webgl_loader_taskmanager.html b/examples/webgl_loader_taskmanager.html index b17b3348c42a61..6b50437fbccb9a 100644 --- a/examples/webgl_loader_taskmanager.html +++ b/examples/webgl_loader_taskmanager.html @@ -25,41 +25,41 @@ import { MaterialHandler } from "./jsm/loaders/obj2/shared/MaterialHandler.js"; import { TransferableUtils } from "./jsm/loaders/obj2/utils/TransferableUtils.js"; - const workerInitFunction = function ( id, config ) { - self.storage = { + const workerInitFunction = function ( context, id, config ) { + context.storage = { whoami: id, }; - self.postMessage( { + context.postMessage( { cmd: "init", id: id } ); }; - const workerExecFunction = function ( id, config ) { + const workerExecFunction = function ( context, id, config ) { let bufferGeometry = new THREE.SphereBufferGeometry( 40, 64, 64 ); - let vertexBA = bufferGeometry.getAttribute( 'position' ) ; + let vertexBA = bufferGeometry.getAttribute( 'position' ); let indexBA = bufferGeometry.getIndex(); let colorBA = bufferGeometry.getAttribute( 'color' ); let normalBA = bufferGeometry.getAttribute( 'normal' ); let uvBA = bufferGeometry.getAttribute( 'uv' ); let vertexArray = vertexBA.array; - for ( let i = 0; i < vertexArray.length; i++ ) { + for ( let i = 0; i < vertexArray.length; i ++ ) { vertexArray[ i ] = vertexArray[ i ] * Math.random() * 0.48; } let vertexFA = vertexArray; - let indexUA = ( indexBA !== null && indexBA !== undefined ) ? indexBA.array: null; - let colorFA = ( colorBA !== null && colorBA !== undefined ) ? colorBA.array: null; - let normalFA = ( normalBA !== null && normalBA !== undefined ) ? normalBA.array: null; - let uvFA = ( uvBA !== null && uvBA !== undefined ) ? uvBA.array: null; + let indexUA = (indexBA !== null && indexBA !== undefined) ? indexBA.array : null; + let colorFA = (colorBA !== null && colorBA !== undefined) ? colorBA.array : null; + let normalFA = (normalBA !== null && normalBA !== undefined) ? normalBA.array : null; + let uvFA = (uvBA !== null && uvBA !== undefined) ? uvBA.array : null; - self.postMessage( { + context.postMessage( { cmd: 'exec', type: 'mesh', meshName: 'tmProto' + config.count, @@ -74,31 +74,17 @@ uvs: uvFA, }, materials: { - materialNames: [ 'meshNormalMaterial' ] + materialNames: ['meshNormalMaterial'] } }, - [ 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 ); - }; - - const workerManageCom = function ( message ) { - let payload = message.data; - if ( payload.cmd === 'init' ) { - - init( payload.id, payload.config ); - - } - else if ( payload.cmd === 'execute' ) { - - execute( payload.id, payload.config ); - - } - }; + } class TaskManagerPrototypeExample { @@ -128,7 +114,8 @@ materialHandler.addMaterials( { meshNormalMaterial: meshNormalMaterial }, true ) this.meshReceiver = new MeshReceiver( materialHandler ); - this.taskNames = [ 'tmProtoExample', 'tmProtoExampleJsm', 'tmProtoExampleJsmNoThree' ]; + this.taskNames = []; + this.tasksToUse = []; this.executions = []; this.meshCount = 0; this.lastDeletedMesh = 0; @@ -178,36 +165,65 @@ } - async initContent () { + initContent () { + let torus = new THREE.TorusBufferGeometry( 25, 8, 16, 100 ); let torusPayload = TransferableUtils.packageBufferGeometry( torus, 'torus', 0 ); - this.taskManager.registerType( this.taskNames[ 0 ], 4, workerInitFunction, workerExecFunction, workerManageCom, [ "../build/three.js" ] ); - this.taskManager.registerTypeJsm( this.taskNames[ 1 ], 4, './jsm/taskmanager/tmJsmExample.js' ); - this.taskManager.registerTypeJsm( this.taskNames[ 2 ], 4, './jsm/taskmanager/tmJsmExampleNoThree.js' ); - let available = await this.taskManager.initType( this.taskNames[ 0 ], { param1: 'param1value' } ); - let availableJsm = await this.taskManager.initType( this.taskNames[ 1 ], { param1: 'param1value' } ); - let availableJsmNoThree = await this.taskManager.initType( this.taskNames[ 2 ], torusPayload, torusPayload.transferables ); + this.taskNames = [ 'tmProtoExample', 'tmProtoExampleMain', 'tmProtoExampleJsm', 'tmProtoExampleJsmNoThree' ]; + this.tasksToUse = [ this.taskNames[ 0 ], this.taskNames[ 1 ], this.taskNames[ 2 ], this.taskNames[ 3 ] ]; + let awaiting = []; - console.time( 'start' ); + if ( this.tasksToUse.includes( this.taskNames[ 0 ] ) ) { + + this.taskManager.registerType( this.taskNames[ 0 ], 4, workerInitFunction, workerExecFunction, null, ["../build/three.js"] ); + awaiting.push( this.taskManager.initType( this.taskNames[ 0 ], { param1: 'param1value' } ).catch( e => console.error( e ) ) ); + + } + if ( this.tasksToUse.includes( this.taskNames[ 1 ] ) ) { + + this.taskManager.registerType( this.taskNames[ 1 ], 0, workerInitFunction, workerExecFunction, null ); + awaiting.push( this.taskManager.initType( this.taskNames[ 1 ], { param1: 'param1value' } ).catch( e => console.error( e ) ) ); + } + if ( this.tasksToUse.includes( this.taskNames[ 2 ] ) ) { + + this.taskManager.registerTypeJsm( this.taskNames[ 2 ], 4, './jsm/taskmanager/tmJsmExample.js' ); + awaiting.push( this.taskManager.initType( this.taskNames[ 2 ], { param1: 'param1value' } ).catch( e => console.error( e ) ) ); + + } + if ( this.tasksToUse.includes( this.taskNames[ 3 ] ) ) { + + this.taskManager.registerTypeJsm( this.taskNames[ 3 ], 4, './jsm/taskmanager/tmJsmExampleNoThree.js' ); + awaiting.push( this.taskManager.initType( this.taskNames[ 3 ], torusPayload, torusPayload.transferables ).catch( e => console.error( e ) ) ); + + } + return Promise.all( awaiting ); + + } + + async executeWorkers () { + + console.time( 'start' ); let globalCount = 0; - let taskNameIndex = 0; + let taskToUseIndex = 0; for ( let j = 0; j < this.loopCount; j++ ) { console.time( 'Completed ' + ( this.maxPerLoop + j * this.maxPerLoop ) ); for ( let i = 0; i < this.maxPerLoop; i ++ ) { - this._storeAddTaskPromise( taskNameIndex, globalCount ); + this._storeAddTaskPromise( taskToUseIndex, globalCount ); globalCount++; - taskNameIndex++; - if ( taskNameIndex === this.taskNames.length ) taskNameIndex = 0; + taskToUseIndex++; + if ( taskToUseIndex === this.tasksToUse.length ) taskToUseIndex = 0; } - await Promise.all( this.executions ); - this.executions = []; - console.timeEnd( 'Completed ' + ( this.maxPerLoop + j * this.maxPerLoop ) ); + await Promise.all( this.executions ).then( x => { + this.executions = []; + console.timeEnd( 'Completed ' + ( this.maxPerLoop + j * this.maxPerLoop ) ); + + } ); } this.taskManager.dispose(); console.timeEnd( 'start' ); @@ -216,11 +232,11 @@ _storeAddTaskPromise( taskNameIndex, globalCount ) { - this.executions.push( this.taskManager.addTask( this.taskNames[ taskNameIndex ], 1, { count: globalCount } ).then( data => this.processMessage( data ) ).catch( e => console.error( e ) ) ); + this.executions.push( this.taskManager.addTask( this.tasksToUse[ taskNameIndex ], 1, { count: globalCount } ).then( data => this._processMessage( data ) ).catch( e => console.error( e ) ) ); } - processMessage ( payload ) { + _processMessage ( payload ) { switch ( payload.cmd ) { case 'init': console.log( 'Init Completed: ' + payload.id ); @@ -230,17 +246,17 @@ if ( payload.type === 'mesh' ) { let meshes = this.meshReceiver.buildMeshes( payload ); - this.addMesh( meshes[ 0 ], payload.params ); + this._addMesh( meshes[ 0 ], payload.params ); } else { let mesh = new THREE.Mesh( new THREE.SphereBufferGeometry( 5, 32, 32 ) ); mesh.name = payload.meshName; - this.addMesh( mesh, {} ) + this._addMesh( mesh, {} ) } - this.cleanMeshes(); + this._cleanMeshes(); break; default: @@ -249,7 +265,7 @@ } } - addMesh( mesh, params ) { + _addMesh( mesh, params ) { let pos = new THREE.Vector3( this.baseFactor * Math.random(), this.baseFactor * Math.random(), this.baseFactor * Math.random() ); pos.applyAxisAngle( this.baseVectorX, 2 * Math.PI * Math.random() ); @@ -266,7 +282,7 @@ } - cleanMeshes() { + _cleanMeshes() { if ( this.meshCount > this.numberOfMeshesToKeep && this.meshCount - this.lastDeletedMesh >= this.numberOfMeshesToKeep ) { @@ -324,7 +340,6 @@ if ( !this.renderer.autoClear ) this.renderer.clear(); this.controls.update(); this.renderer.render( this.scene, this.camera ); - } } @@ -345,8 +360,10 @@ console.log( 'Starting initialisation phase...' ); app.initGL(); app.resizeDisplayGL(); - app.initContent(); - + app.initContent().then( x => { + console.log( 'All tasks habe been initialized.' ); + app.executeWorkers(); + } ); render();