Browse Source

DRACOLoader: Support repeated loading.

Don McCurdy 5 years ago
parent
commit
81a642592e
2 changed files with 94 additions and 8 deletions
  1. 47 4
      examples/js/loaders/DRACOLoader.js
  2. 47 4
      examples/jsm/loaders/DRACOLoader.js

+ 47 - 4
examples/js/loaders/DRACOLoader.js

@@ -124,10 +124,6 @@ THREE.DRACOLoader.prototype = Object.assign( Object.create( THREE.Loader.prototy
 
 	decodeGeometry: function ( buffer, taskConfig ) {
 
-		var worker;
-		var taskID = this.workerNextTaskID ++;
-		var taskCost = buffer.byteLength;
-
 		// TODO: For backward-compatibility, support 'attributeTypes' objects containing
 		// references (rather than names) to typed array constructors. These must be
 		// serialized before sending them to the worker.
@@ -143,6 +139,43 @@ THREE.DRACOLoader.prototype = Object.assign( Object.create( THREE.Loader.prototy
 
 		}
 
+		//
+
+		var taskKey = JSON.stringify( taskConfig );
+
+		// Check for an existing task using this buffer. A transferred buffer cannot be transferred
+		// again from this thread.
+		if ( THREE.DRACOLoader.taskCache.has( buffer ) ) {
+
+			var cachedTask = THREE.DRACOLoader.taskCache.get( buffer );
+
+			if ( cachedTask.key === taskKey ) {
+
+				return cachedTask.promise;
+
+			} else if ( buffer.byteLength === 0 ) {
+
+				// Technically, it would be possible to wait for the previous task to complete,
+				// transfer the buffer back, and decode again with the second configuration. That
+				// is complex, and I don't know of any reason to decode a Draco buffer twice in
+				// different ways, so this is left unimplemented.
+				throw new Error(
+
+					'THREE.DRACOLoader: Unable to re-decode a buffer with different ' +
+					'settings. Buffer has already been transferred.'
+
+				);
+
+			}
+
+		}
+
+		//
+
+		var worker;
+		var taskID = this.workerNextTaskID ++;
+		var taskCost = buffer.byteLength;
+
 		// Obtain a worker and assign a task, and construct a geometry instance
 		// when the task completes.
 		var geometryPending = this._getWorker( taskID, taskCost )
@@ -177,6 +210,14 @@ THREE.DRACOLoader.prototype = Object.assign( Object.create( THREE.Loader.prototy
 
 			} );
 
+		// Cache the task result.
+		THREE.DRACOLoader.taskCache.set( buffer, {
+
+			key: taskKey,
+			promise: geometryPending
+
+		} );
+
 		return geometryPending;
 
 	},
@@ -604,6 +645,8 @@ THREE.DRACOLoader.DRACOWorker = function () {
 
 };
 
+THREE.DRACOLoader.taskCache = new WeakMap();
+
 /** Deprecated static methods */
 
 /** @deprecated */

+ 47 - 4
examples/jsm/loaders/DRACOLoader.js

@@ -131,10 +131,6 @@ DRACOLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 	decodeGeometry: function ( buffer, taskConfig ) {
 
-		var worker;
-		var taskID = this.workerNextTaskID ++;
-		var taskCost = buffer.byteLength;
-
 		// TODO: For backward-compatibility, support 'attributeTypes' objects containing
 		// references (rather than names) to typed array constructors. These must be
 		// serialized before sending them to the worker.
@@ -150,6 +146,43 @@ DRACOLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 		}
 
+		//
+
+		var taskKey = JSON.stringify( taskConfig );
+
+		// Check for an existing task using this buffer. A transferred buffer cannot be transferred
+		// again from this thread.
+		if ( DRACOLoader.taskCache.has( buffer ) ) {
+
+			var cachedTask = DRACOLoader.taskCache.get( buffer );
+
+			if ( cachedTask.key === taskKey ) {
+
+				return cachedTask.promise;
+
+			} else if ( buffer.byteLength === 0 ) {
+
+				// Technically, it would be possible to wait for the previous task to complete,
+				// transfer the buffer back, and decode again with the second configuration. That
+				// is complex, and I don't know of any reason to decode a Draco buffer twice in
+				// different ways, so this is left unimplemented.
+				throw new Error(
+
+					'THREE.DRACOLoader: Unable to re-decode a buffer with different ' +
+					'settings. Buffer has already been transferred.'
+
+				);
+
+			}
+
+		}
+
+		//
+
+		var worker;
+		var taskID = this.workerNextTaskID ++;
+		var taskCost = buffer.byteLength;
+
 		// Obtain a worker and assign a task, and construct a geometry instance
 		// when the task completes.
 		var geometryPending = this._getWorker( taskID, taskCost )
@@ -184,6 +217,14 @@ DRACOLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 			} );
 
+		// Cache the task result.
+		DRACOLoader.taskCache.set( buffer, {
+
+			key: taskKey,
+			promise: geometryPending
+
+		} );
+
 		return geometryPending;
 
 	},
@@ -611,6 +652,8 @@ DRACOLoader.DRACOWorker = function () {
 
 };
 
+DRACOLoader.taskCache = new WeakMap();
+
 /** Deprecated static methods */
 
 /** @deprecated */