Skip to content

Commit

Permalink
Merge pull request #6420 from AnalyticalGraphicsInc/wasm
Browse files Browse the repository at this point in the history
Speed up Draco loading
  • Loading branch information
lilleyse authored Apr 24, 2018
2 parents 4827168 + 4d2c551 commit 757d7b9
Show file tree
Hide file tree
Showing 20 changed files with 3,610 additions and 3,365 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Change Log
* Added `Math.log2` to compute the base 2 logarithm of a number.
* Added 'PeliasGeocoderService', which provides geocoding via a [Pelias](https://pelias.io) server.
* Added `GeocodeType` enum and use it as an optional parameter to all `GeocoderService` instances to differentiate between autocomplete and search requests.
* Added `initWebAssemblyModule` function to `TaskProcessor` to load a Web Assembly module in a web worker. [#6420](https://github.com/AnalyticalGraphicsInc/cesium/pull/6420)
* Added `supportsWebAssembly` function to `FeatureDetection` to check if a browser supports loading Web Assembly modules. [#6420](https://github.com/AnalyticalGraphicsInc/cesium/pull/6420)
* Improved `MapboxImageryProvider` performance by 300% via `tiles.mapbox.com` subdomain switching. [#6426](https://github.com/AnalyticalGraphicsInc/cesium/issues/6426)
* Added ability to invoke `sampleTerrain` from node.js to enable offline terrain sampling

Expand All @@ -18,6 +20,7 @@ Change Log
* Fixed glTF support to handle meshes with and without tangent vectors, and with/without morph targets, sharing one material. [#6421](https://github.com/AnalyticalGraphicsInc/cesium/pull/6421)
* Fixed glTF support to handle skinned meshes when no skin is supplied. [#6061](https://github.com/AnalyticalGraphicsInc/cesium/issues/6061)
* Allow loadWithXhr to work with string URLs in a web worker.
* Updated to Draco 1.3.0 and implemented faster loading of Draco compressed glTF assets in browsers that support Web Assembly. [#6420](https://github.com/AnalyticalGraphicsInc/cesium/pull/6420)
* `GroundPrimitive`s and `ClassificationPrimitive`s will become ready when `show` is `false`. [#6428](https://github.com/AnalyticalGraphicsInc/cesium/pull/6428)
* Fix Firefox WebGL console warnings. [#5912](https://github.com/AnalyticalGraphicsInc/cesium/issues/5912)
* Fix parsing Cesium.js in older browsers that do not support all TypedArray types. [#6396](https://github.com/AnalyticalGraphicsInc/cesium/pull/6396)
Expand Down
11 changes: 11 additions & 0 deletions Source/Core/FeatureDetection.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,5 +280,16 @@ define([
return typeof Worker !== 'undefined';
};

/**
* Detects whether the current browser supports Web Assembly.
*
* @returns {Boolean} true if the browsers supports Web Assembly, false if not.
*
* @see {@link https://developer.mozilla.org/en-US/docs/WebAssembly}
*/
FeatureDetection.supportsWebAssembly = function() {
return typeof WebAssembly !== 'undefined';
};

return FeatureDetection;
});
74 changes: 74 additions & 0 deletions Source/Core/TaskProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ define([
'./destroyObject',
'./DeveloperError',
'./Event',
'./FeatureDetection',
'./getAbsoluteUri',
'./isCrossOriginUrl',
'./Resource',
'./RuntimeError',
'require'
], function(
Expand All @@ -18,8 +20,10 @@ define([
destroyObject,
DeveloperError,
Event,
FeatureDetection,
getAbsoluteUri,
isCrossOriginUrl,
Resource,
RuntimeError,
require) {
'use strict';
Expand Down Expand Up @@ -161,6 +165,34 @@ define([
return worker;
}

function getWebAssemblyLoaderConfig(processor, wasmOptions) {
var config = {
modulePath : undefined,
wasmBinaryFile : undefined,
wasmBinary : undefined
};

// Web assembly not supported, use fallback js module if provided
if (!FeatureDetection.supportsWebAssembly()) {
if (!defined(wasmOptions.fallbackModulePath)) {
throw new RuntimeError('This browser does not support Web Assembly, and no backup module was provided for ' + processor._workerName);
}

config.modulePath = buildModuleUrl(wasmOptions.fallbackModulePath);
return when.resolve(config);
}

config.modulePath = buildModuleUrl(wasmOptions.modulePath);
config.wasmBinaryFile = buildModuleUrl(wasmOptions.wasmBinaryFile);

return Resource.fetchArrayBuffer({
url: config.wasmBinaryFile
}).then(function (arrayBuffer) {
config.wasmBinary = arrayBuffer;
return config;
});
}

/**
* A wrapper around a web worker that allows scheduling tasks for a given worker,
* returning results asynchronously via a promise.
Expand Down Expand Up @@ -245,6 +277,48 @@ define([
});
};

/**
* Posts a message to a web worker with configuration to initialize loading
* and compiling a web assembly module asychronously, as well as an optional
* fallback JavaScript module to use if Web Assembly is not supported.
*
* @param {Object} [webAssemblyOptions] An object with the following properties:
* @param {String} [webAssemblyOptions.modulePath] The path of the web assembly JavaScript wrapper module.
* @param {String} [webAssemblyOptions.wasmBinaryFile] The path of the web assembly binary file.
* @param {String} [webAssemblyOptions.fallbackModulePath] The path of the fallback JavaScript module to use if web assembly is not supported.
* @returns {Promise.<Object>} A promise that resolves to the result when the web worker has loaded and compiled the web assembly module and is ready to process tasks.
*/
TaskProcessor.prototype.initWebAssemblyModule = function (webAssemblyOptions) {
if (!defined(this._worker)) {
this._worker = createWorker(this);
}

var deferred = when.defer();
var processor = this;
var worker = this._worker;
getWebAssemblyLoaderConfig(this, webAssemblyOptions).then(function(wasmConfig) {
return when(canTransferArrayBuffer(), function(canTransferArrayBuffer) {
var transferableObjects;
var binary = wasmConfig.wasmBinary;
if (defined(binary) && canTransferArrayBuffer) {
transferableObjects = [binary];
}

worker.onmessage = function(event) {
worker.onmessage = function(event) {
completeTask(processor, event.data);
};

deferred.resolve(event.data);
};

worker.postMessage({ webAssemblyConfig : wasmConfig }, transferableObjects);
});
});

return deferred;
};

/**
* Returns true if this object was destroyed; otherwise, false.
* <br /><br />
Expand Down
16 changes: 15 additions & 1 deletion Source/Scene/DracoLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,18 @@ define([

// Exposed for testing purposes
DracoLoader._decoderTaskProcessor = undefined;
DracoLoader._taskProcessorReady = false;
DracoLoader._getDecoderTaskProcessor = function () {
if (!defined(DracoLoader._decoderTaskProcessor)) {
DracoLoader._decoderTaskProcessor = new TaskProcessor('decodeDraco', DracoLoader._maxDecodingConcurrency);
var processor = new TaskProcessor('decodeDraco', DracoLoader._maxDecodingConcurrency);
processor.initWebAssemblyModule({
modulePath : 'ThirdParty/Workers/draco_wasm_wrapper.js',
wasmBinaryFile : 'ThirdParty/draco_decoder.wasm',
fallbackModulePath : 'ThirdParty/Workers/draco_decoder.js'
}).then(function () {
DracoLoader._taskProcessorReady = true;
});
DracoLoader._decoderTaskProcessor = processor;
}

return DracoLoader._decoderTaskProcessor;
Expand Down Expand Up @@ -85,6 +94,11 @@ define([
}

function scheduleDecodingTask(decoderTaskProcessor, model, loadResources, context) {
if (!DracoLoader._taskProcessorReady) {
// The task processor is not ready to schedule tasks
return;
}

var taskData = loadResources.primitivesToDecode.peek();
if (!defined(taskData)) {
// All primitives are processing
Expand Down
32 changes: 32 additions & 0 deletions Source/ThirdParty/Workers/draco_decoder.js

Large diffs are not rendered by default.

Loading

0 comments on commit 757d7b9

Please sign in to comment.