WebGL Streaming Instantiation Support - Errors on Loading in Browser

I was excited to see that in Unity 2019.1 Alpha 9, WebGL now has an option to enable Wasm streaming instanation. However it looks like there's a bit more involved than simply ticking the box in the player settings to have it working.

on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)

failed to asynchronously prepare wasm

uncaught exception: abort("abort(\"on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)\")

Unfortunately the ArrayBuffer fallback appears to simply fail.

Reading the WebAssembly spec as well as the Emscripten compile instructions, it appears that for streaming instantiation to work the files need to have their Content-Type set on the server as application/wasm. Sadly this doesn't appear to change the outcome.

Unity Technologies

I was excited to see that in Unity 2019.1 Alpha 9, WebGL now has an option to enable Wasm streaming instanation. However it looks like there's a bit more involved than simply ticking the box in the player settings to have it working.

on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)

failed to asynchronously prepare wasm

uncaught exception: abort("abort(\"on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)\")

Unfortunately the ArrayBuffer fallback appears to simply fail.

Reading the WebAssembly spec as well as the Emscripten compile instructions, it appears that for streaming instantiation to work the files need to have their Content-Type set on the server as application/wasm. Sadly this doesn't appear to change the outcome.

To be honest, I only tested it on our self hosted apache server so far, see this build. Basically you need to add .wasm to the mime types and make sure it's configured according to the compression selected in PlayerSettings.WebGL.compression.
For brotli, the .htacces looks like:

Code (csharp):

<IfModule mod_mime.c>

AddEncoding br .unityweb

AddType application/wasm .wasm

AddEncoding br .wasm

AddOutputFilterByType DEFLATE application/wasm

</IfModule>

similarly, for gzip:

Code (csharp):

<IfModule mod_mime.c>

AddEncoding gzip .unityweb

AddType application/wasm .wasm

AddEncoding gzip .wasm

AddOutputFilterByType DEFLATE application/wasm

</IfModule>

So for IIS you need to do something similar. We will try to update the docs as soon as possible.

One known issue is that we are not currently caching the wasm file but this should be fixed in the coming weeks.

I need to know - is it work? Is it help with background (un-focused tab) download and initialize webgl, and not freezes for user focus (unity 5.6 and 2017 is freeze before final init, and wait for user focus tab)

Unity Technologies

This is not a known issue. Unity 2019.1.0a13 is out now, would you mind trying with that?

I need to know - is it work? Is it help with background (un-focused tab) download and initialize webgl, and not freezes for user focus (unity 5.6 and 2017 is freeze before final init, and wait for user focus tab)

Click to expand...

If you are referring to the freeze at the very end of loading, it is not fixed by wasm streaming.

Hi @Marco-Trivellato , We're about to launch a webgl game, and we more or less successfully upgraded to Unity2019.1b5.

We are having similar problems with getting data streaming to work. I was able to get a local Apache server up and running and with your config it *does* work. I got it to do the brotli compression on both .unityweb files and have the streaming compilation succeed.

The issue I have is when I want to put it up on our CDN I'm not sure exactly what's breaking where. It's the exact same files as on our local server which work, but break on the CDN. I get the error: wasm streaming compile failed: CompileError: AsyncCompile: Wasm decoding failed: expected magic word 00 61 73 6d, found 6b 8d 00 55 @+0

However, looking at the headers it seems that the .wasm file does indeed have
content-encoding: br set. Where I think it's going wrong is that the .wasm file then also assumes that the .unityweb files are also brotli encoded, which they are not (because I haven't convinced the CDN to do it yet ;-). Would that be a possible explanation of the Wasm decode failure?
(Link to the example that is failing is https://arxarcana.io/streamingtest/index.html)

Is there a way to check that the wasm file is correctly brotli compressed? Should I write some custom javascript to compare the original file with the one that's downloaded for example?

The unity build (as of Unity 2019.1.0b5) with either gzip or brotli enabled *compresses* the wasm file. Some CDNs when they see that the content type is application/wasm will compress the wasm file a *second time*, the browser gets it and decompresses it only once. This will lead to it neither doing streaming compilation nor actually working at all.

The line that Marco put into his apache config file: AddOutputFilterByType DEFLATE application/wasm will deflate a compressed wasm build as it is delivered to the client over the wire. In our case that means that apache was sending 26megs of uncompressed wasm instead of 7 megs of compressed wasm which may not be what you want in a production environment.

The most success I've had is to create an uncompressed build, and have the CDN compress the wasm file for you. With this approach I was indeed able to shave anywhere from 1 second to 6 seconds off our WebGL build. I now need to figure out how to tell our CDN to *also* compressed the uncompressed .unityweb files coming out of an uncompressed unity build, so more time might yet be saved.

If someone else has more success or thinks my numbers should be better let me know!

We are still getting the "unsupported MIME type" and "magic number" errors in 2019.1.0b5. I'm going to request that our Hosting company adjust our server to to handle the Mime issue, but:

Is it ok/possible to set our Apache server to handle both Brotli AND gzip? We use Brotli for our public build, but gzip for our dev builds and rapid prototyping? I know we tried setting it up to use Brotli before and it created a lot of problems so I'm more cautious this time.

Is the magic number bug nearly fixed?

I'm also curious why we have to set the mime to use WebAssembly when we're already using WebAssembly just fine. Is this just for the Streaming aspect?

I'm very eager to see what kind of increases this might get us for our WebGL builds.

The file is served with Content-Encoding: br, and Content-Type: application/wasm as is proper here. This should trigger the browser to decompress the file upon receiving it, but it looks like it doesn't.

One thing to try, can you rename the file suffix from .wasm to .wasm.br? (and double-check that Content-Encoding: br, and Content-Type: application/wasm are still being passed), and edit the loader JS files to download the .wasm.br version instead of the .wasm file. I wonder if browsers require that Brotli files are served with file suffix .br in order to trigger the decompression at browser end.

Decompressing the downloaded wasm brotli file locally with 'brotli' decompressor works out ok, although the command-line decompressor requires that the file ends with suffix .br, otherwise it refuses to process it. Decompressed .wasm file is 27.9MB, and starts with bytes 00 61 73 6D.

Is it ok/possible to set our Apache server to handle both Brotli AND gzip?

Click to expand...

It should be possible, but will need some manual work on the build output that Unity currently produces. The general scheme is to place two files to CDN: a.wasm.gz and a.wasm.br, and have browser JS download file "a.wasm", and depending on what client browser advertises under "Accept-Encoding:" when it is doing the request, the web server should be configured to redirect to serve a.wasm.br instead if "Accept-Encoding: br" had been specified, or a.wasm.gz if "Accept-Encoding: gzip" had been specified.

I'm also curious why we have to set the mime to use WebAssembly when we're already using WebAssembly just fine. Is this just for the Streaming aspect?

Click to expand...

Yes, the MIME application/wasm is only needed to tell the browser that the incoming data is wasm, so that it knows to start streaming compilation early. If MIME type is wrong, browser will then not know to do streaming compilation, but will have to wait to get the whole file to compile.

Oops...

"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.