소스 검색

BasisTextureLoader: Fix severe work distribution imbalance

When used from GLTF loader, it's common for BasisTextureLoader promises
to be created in quick succession for a number of textures.

What happens is that the methods wait until the transcoder is loaded,
and then call _getWorker in succession. After each _getWorker call
succeeds, the continuation for the promise is scheduled - however, the
worker task cost is only adjusted when that continuation is ran, and the
next _getWorker call runs immediately after.

As a result, the _taskLoad-based sorting doesn't work, and most textures
are assigned to the last worker, which means that the decode is mostly
single-threaded.

This change fixes this by integrating cost adjustment into _getWorker
(renamed to _allocateWorker for clarity); we also don't need _taskCosts
anymore because we can close over the taskCost local instead.

Also fix the problem where we were creating redundant object URLs for
the transcoder binary because of many calls to _initTranscoder (during
_getWorker) during which the transcoder promise is setup but the binary
hasn't been loaded yet.
Arseny Kapoulkine 5 년 전
부모
커밋
f19d9795a6
2개의 변경된 파일22개의 추가작업 그리고 18개의 파일을 삭제
  1. 11 9
      examples/js/loaders/BasisTextureLoader.js
  2. 11 9
      examples/jsm/loaders/BasisTextureLoader.js

+ 11 - 9
examples/js/loaders/BasisTextureLoader.js

@@ -119,7 +119,9 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 		var worker;
 		var taskID;
 
-		var texturePending = this._getWorker()
+		var taskCost = buffer.byteLength;
+
+		var texturePending = this._allocateWorker( taskCost )
 			.then( ( _worker ) => {
 
 				worker = _worker;
@@ -128,8 +130,6 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 				return new Promise( ( resolve, reject ) => {
 
 					worker._callbacks[ taskID ] = { resolve, reject };
-					worker._taskCosts[ taskID ] = buffer.byteLength;
-					worker._taskLoad += worker._taskCosts[ taskID ];
 
 					worker.postMessage( { type: 'transcode', id: taskID, buffer }, [ buffer ] );
 
@@ -181,9 +181,8 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 				if ( worker && taskID ) {
 
-					worker._taskLoad -= worker._taskCosts[ taskID ];
+					worker._taskLoad -= taskCost;
 					delete worker._callbacks[ taskID ];
-					delete worker._taskCosts[ taskID ];
 
 				}
 
@@ -195,7 +194,7 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 	_initTranscoder: function () {
 
-		if ( ! this.transcoderBinary ) {
+		if ( ! this.transcoderPending ) {
 
 			// Load transcoder wrapper.
 			var jsLoader = new THREE.FileLoader( this.manager );
@@ -239,7 +238,7 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 	},
 
-	_getWorker: function () {
+	_allocateWorker: function ( taskCost ) {
 
 		return this._initTranscoder().then( () => {
 
@@ -248,7 +247,6 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 				var worker = new Worker( this.workerSourceURL );
 
 				worker._callbacks = {};
-				worker._taskCosts = {};
 				worker._taskLoad = 0;
 
 				worker.postMessage( {
@@ -290,7 +288,11 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 			}
 
-			return this.workerPool[ this.workerPool.length - 1 ];
+			var worker = this.workerPool[ this.workerPool.length - 1 ];
+
+			worker._taskLoad += taskCost;
+
+			return worker;
 
 		} );
 

+ 11 - 9
examples/jsm/loaders/BasisTextureLoader.js

@@ -132,7 +132,9 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 		var worker;
 		var taskID;
 
-		var texturePending = this._getWorker()
+		var taskCost = buffer.byteLength;
+
+		var texturePending = this._allocateWorker( taskCost )
 			.then( ( _worker ) => {
 
 				worker = _worker;
@@ -141,8 +143,6 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 				return new Promise( ( resolve, reject ) => {
 
 					worker._callbacks[ taskID ] = { resolve, reject };
-					worker._taskCosts[ taskID ] = buffer.byteLength;
-					worker._taskLoad += worker._taskCosts[ taskID ];
 
 					worker.postMessage( { type: 'transcode', id: taskID, buffer }, [ buffer ] );
 
@@ -194,9 +194,8 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 				if ( worker && taskID ) {
 
-					worker._taskLoad -= worker._taskCosts[ taskID ];
+					worker._taskLoad -= taskCost;
 					delete worker._callbacks[ taskID ];
-					delete worker._taskCosts[ taskID ];
 
 				}
 
@@ -208,7 +207,7 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 	_initTranscoder: function () {
 
-		if ( ! this.transcoderBinary ) {
+		if ( ! this.transcoderPending ) {
 
 			// Load transcoder wrapper.
 			var jsLoader = new FileLoader( this.manager );
@@ -252,7 +251,7 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 	},
 
-	_getWorker: function () {
+	_allocateWorker: function ( taskCost ) {
 
 		return this._initTranscoder().then( () => {
 
@@ -261,7 +260,6 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 				var worker = new Worker( this.workerSourceURL );
 
 				worker._callbacks = {};
-				worker._taskCosts = {};
 				worker._taskLoad = 0;
 
 				worker.postMessage( {
@@ -303,7 +301,11 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 			}
 
-			return this.workerPool[ this.workerPool.length - 1 ];
+			var worker = this.workerPool[ this.workerPool.length - 1 ];
+
+			worker._taskLoad += taskCost;
+
+			return worker;
 
 		} );