DracoCompression can not work inside web worker thread

see this playground:

https://www.babylonjs-playground.com/#N3EK4B#13

there is no error or warning displayed in the console, it’s rare.

@bghgary really sorry for interrupting your gdc trip again.

@bghgary It looks like the script loading promise for Draco never returns in the worker if that can be of any help.

I have a super old branch that puts Draco into web workers: GitHub - bghgary/Babylon.js at draco-web-workers

From my testing before, this actually made the perf worse which was a bit surprising, which is why I didn’t submit a PR.

In any case, in your PG, I think the reason why Draco doesn’t work is because the Draco scripts aren’t loaded in the web worker context. DecoderAvailable property is a bit misleading in that it doesn’t check the presence of the module itself. I will fix that.

1 Like

@bghgary Thanks for the reply.

I did see the branch you mentioned above, I think maybe the performance issue is due to Webassembly.

I also tried the draco decoder in pure javascript mode in Three.js and in web workers, it works very well, and I don’t see any critical performance issue.

So I also tried this:

            BABYLON.DracoCompression.Configuration = {
                decoder: {
                    fallbackUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js",
                }
            };

to make it work only under javascript mode, but this playground also failed, see https://www.babylonjs-playground.com/#N3EK4B#16

In my case even pure javascript decompression mode in web workers, is still faster than webassembly in main thread. So I really need web workers more than webassembly.

And we can see draco_decoder_gltf.wasm is loaded in the Network panel of DevTools.

Maybe we should make it more clearer to let user decide which mode to use, webassembly with javascript fallback, or only javascript.

I agree: That is something we have to look into

I will revive my branch and try to make it work again. In theory, because Draco can now run on multiple threads, it should pretty much always run better than on the main thread.

All of these options are already possible. If you null out the wasm version, the code should pick the javascript version.

@hjlld Draco with web workers is in. Let me know if it works for you.

1 Like

Thank you @bghgary, i’ll try it later!

@bghgary now the code below has influence on server side rendering with NullEngine, especially on node.js, because there’s no navigator object.

some other classes, like WebXRSessionMananger and etc, also has this issue, but obviously they seems like never to be used under NullEngine, but DracoCompression does.

or should we let developer create workers, babylon only guarantee that BABYLON.DracoCompression is able to work properly inside worker thread?

thank you a lot, sorry for bothering yo so much.

@hjlld is it crashing with null engine ? cause our loader unit tests rely on the loader and null engine without issues.

Trying to better understand the issue as @bghgary is off this week so that I could try to solve it before the 4.0 release.

yes… @sebavan

here’s my index.js with npm i babylonjs@4.0.0-beta.4

const BABYLON = require('babylonjs/babylon.max')

let engine = new BABYLON.NullEngine()

throw error after node index.js:

L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:85936
        var hardwareConcurrency = navigator && navigator.hardwareConcurrency;
                                  ^

ReferenceError: navigator is not defined
    at Function../Meshes/Compression/dracoCompression.ts.DracoCompression.GetDefaultNumWorkers (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:85936:35)
    at L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:86159:59
    at Module../Meshes/Compression/dracoCompression.ts (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:86161:2)
    at __webpack_require__ (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:30:30)
    at Module../Meshes/Compression/index.ts (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:86176:75)
    at __webpack_require__ (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:30:30)
    at Module../Meshes/index.ts (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:91027:76)
    at __webpack_require__ (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:30:30)
    at Module../index.ts (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:140617:72)
    at __webpack_require__ (L:\myCode\babylonjs-nullengine\node_modules\babylonjs\babylon.max.js:30:30)

or see this online example: Repl.it - UsefulBitterParallelalgorithm

Perfect will be fix in a bit :slight_smile:

1 Like

It will be in next nightly :slight_smile:

1 Like

Thanks for the fix @sebavan. Just a quick note, if navigator is not available, DracoCompression.DefaultNumWorkers defaults to 1 which means it will only use 1 web worker to decode draco meshes and will not be as efficient as it can be. Set this to a higher number if you want to use more web workers.

but what will happen if even the web worker is not available, for example under node.js or some mobile browser

there should be an option to decide to use worker or not.

and sometimes developers want to create workers by themselves, babylon could just guarantee that BABYLON.DracoCompression is able to work properly inside worker thread.

Thank you

I will look into this.

I’m not sure how efficient this will be. The web worker will have to load Babylon and Draco in the worker context and then use DracoCompression to decode into a VertexBuffer. I suppose with tree shaking this can be minimal, but I have no idea if these concepts all work together. Regardless, I will try to make it work.

1 Like

you are very appreciated!!!

It should be working now. Here is a playground that illustrates doing it:

https://www.babylonjs-playground.com/#N3EK4B#20

A couple of notes:

  • By default, DracoCompression will create new web workers (even inside a web worker). Pass in 0 to disable creating web workers and run tasks synchronously.
  • This PG is modified from your original one. One thing to note is that the VertexData object does not marshal from one thread to the main thread with prototypes. It just marshals as a normal object and thus I modified the PG to call BABYLON.VertexData.ImportVertexData to set the vertex data. Also note that this is quite inefficient in terms of loading the scripts, web assembly, copying objects, etc.