Unity 5.0 shipped with a working preview of our WebGL technology in March this year. Since then, Google has disabled (by default) NPAPI support in their Chrome browser (meaning that the Unity Web Player will no longer work there) which is pushing a lot of Unity developers to try out WebGL as an alternative. Some people have already published games using Unity WebGL, but we have also heard from people running into issues porting their existing web player games over. It is important to understand that WebGL and the Web Player are - while targeting the same space - very different platforms with very different technical implementations, which means that not everything which is possible in the Web Player right now will be equally possible in WebGL. Also, it is important to understand that WebGL is a rather new technology with a fast moving ecosystem - so we expect that situation and the possibilities to be very different in maybe a year from now to what they are now.
For this reason, Iâd like to give an overview of things which are happening in the WebGL space, and our future plans around the technology.
WebGL in Unity 5.1
In Unity 5.1 our biggest focus was to fix bugs which would emerge from the initial WebGL release in Unity 5.0. Also, our IL2CPP team has been very busy fixing IL2CPP bugs over the past few month, with a huge number of those fixes and improvements going into 5.1. As WebGL uses IL2CPP as itâs scripting runtime, this also helps the WebGL platform a lot.
While bug fixing was the biggest focus, there is also one new feature in Unity 5.1 of special interest to WebGL users: Crunch texture compression. Crunch texture compression allows compressing textures with JPEG-like compression ratios for transfer/storage, which decompress to GPU-friendly DXTn textures at runtime. This greatly helps reducing the distribution size of WebGL content, as textures are typically the assets with the heaviest size footprint.
But letâs look beyond 5.1 and talk about our plans and visions for the WebGL platform in the future:
âPreviewâ label
Currently, a very common question we get is âWhen will you drop the âPreviewâ labelâ? The answer right now is that we cannot tell. We will drop it when we think the platform is ready. The problem with that statement is that this is as much about our technology being ready for the platform, then about the platform ecosystem being ready for our technology. For this to work as well as we want it to, we need browser vendors to implement and improve some technologies we need. It does not make sense for us to drop the âPreviewâ label because we think that our stuff is ready, when the ecosystem is not - because to our users, what matters is that their content works, and not who is responsible for making it work. This means that readiness is not entirely in our hands in this case. That said, we are talking to all major browser vendors - and we do believe that they are doing a very good job to improve this technology and to get it where we want it to be. Read on for more details.
Note that all the information in this post is based on our current plans and our current understanding of where the WebGL ecosystem is moving. All of this can change in the future. We are not committing to specific release dates for any of these features, and we may decide not to go ahead with some of these at all. If we mention Unity versions we expect features to show up in that is also subject to change.
Memory issues
One of the biggest issues we see people run into with Unity WebGL right now is browsers (especially Chrome) running out of memory on trying to run Unity WebGL content. There are separate issues here:
-
The need to allocate a continuous block of XXX MB of space for the WebGL content. This is the memory Unity will operate on. The size of this can be configured in the WebGL Player settings. This needs to be large enough to fit all the objects and assets Unity will have loaded at a specific point in time. You can use the Memory Profiler in Unity to debug how this space is being used. This needs to be a continuous block of memory in the browserâs heap. If the browser is low on memory, or itâs heap is fragmented, it may fail allocating such a block of memory.
-
Browsers needing too much memory to parse the JavaScript. The JavaScript code emitted by Unity for a WebGL player build is several orders of magnitude larger than other common uses of JavaScript, and JavaScript VMs may require a lot of memory to parse all this code. In particular, Chromeâs V8 sometimes runs into issues with this, causing it to crash, because it cannot allocate enough memory to parse the code. In Firefox, this is not as much of an issue, as Firefox uses asm.js to AOT compile the JavaScript, which has a smaller memory overhead.
For a lot of use cases, this is currently the biggest show-stopping issue on WebGL, and it is not an easy one to fix. Right now, the best we can do on our side is to emit less code. We have been experimenting with this at our last HackWeek, where we had a project to see how far we can reduce the output size of our WebGL export. At the end of the week, we were able to build a simple Unity project to WebGL with a distribution size of 1.2 MB, by improving code stripping, improving compiler settings, and removing things we donât need among other things. While this value is somewhat theoretical, as some of these improvements were made given assumptions we cannot make in general, we did learn a lot from this week, and I expect to see a lot of changes which benefit build output size to be rolled back into Unity starting with version 5.2. Also, we have build tools to visualize which code modules got included in the build, how much code was generated for those, and what caused them to be included. We plan to make these tools available in a future Unity release (5.3 at earliest), which should greatly help users to analyze and optimize their build output sizes. Reducing code output size also helps a lot with startup times, as it reduces the delay needed to parse the code.
But, ultimately, we expect that these memory issues will be helped much more by advances in browser technology. All browsers are moving towards 64-bit builds, which lets them use larger address spaces. And, more importantly, Mozillla, Google and Microsoft are working on a new technology called WebAssembly which packages asm.js code into a bytecode format, which can then be very efficiently be compiled into native code. We are pretty excited about this, as this will greatly reduce load times, memory overhead and distribution size of WebGL content.
Data Compression
Very much related to the memory issues discussed above, distribution size is an issue and currently a source of confusion in Unity WebGL. Distribution size affects download times and memory usage. To keep download times reasonable, we want the data to by transferred in a compressed format. Currently, we rely on the gzip compression support built into the http protocol for that - because that allows the browser to handle decompression âfor freeâ while downloading. Unfortunately, this is rather inconvenient to deal with, as it often requires manual setup on the server side to work correctly - plus gzip is far from efficient compared to more modern compression algorithms.
In the future (currently scheduled for Unity 5.3), Unity will natively support compressing assets in itâs data files on all platforms, which will remove the need to rely on http compression for asset data in WebGL (and we will likely implement some custom compression handling for the code). This will make deploying WebGL content much easier, and as data will stay compressed in memory until it is used, this will also reduce asset memory usage (while in some of our tests actually speeding up asset load times, due to less memory bandwidth used).
Performance
We posted some benchmarks on WebGL performance last year, comparing browsers and native runtimes, which showed decent performance across the board in some areas, and larger gaps both between browser, and between WebGL and native in others. We want to make sure that those gaps will become as small as possible in the future. Most of the benchmarks were we have been seeing large gaps between native and WebGL are in areas which are heavily optimized to use SIMD and/or multithreading, neither of which are available on WebGL right now, but that will change:
-
SIMD.js: SIMD.js is a specification to add SIMD support to the JavaScript language. Mozilla, Google and Microsoft are all planning to support this. We will be able to use this to get the same SIMD performance improvements we get on other platforms right now on WebGL as well.
-
Shared Array Buffers: Shared Array Buffers will let WebWorkers (JavaScriptâs equivalent to threads) share the same memory, which makes it possible to make existing multithreaded code compile to JavaScript. Mozilla has a working implementation of this spec, and they have successfully been running Unity WebGL content with multithreading enabled on this. They ran our benchmark project, with very good results on some of the benchmarks, resulting in several times higher scores when running multi-threaded. Google has also announced plans to add support for Shared Array Buffers
Mobile support
A very common question we get is when we plan to support mobiles with Unity WebGL. While we currently donât do anything in order to prevent running content on mobiles (other than show a warning), in general, success rates are rather low (some high-end Android mobiles yield decent results, but most everyday end-user devices - not so much.). We donât expect to see much change here before the above points on memory and performance see some significant improvements and performance of mobiles will have improved in general, so we cannot give any ETA on mobile support. We do believe that it will inevitably happen as technology progresses in the future, though.
Build times
Another common issue is that WebGL projects take very long to build. Mozilla is working on moving the complete emscripten compiler toolchain into native code (it is currently implemented in a mixture of languages), which we expect to improve build times significantly. In Unity 5.1 we have already seen emscripten updated to a version which moved JavaScript optimizations to native code improving build times compared to 5.0.
Audio
Currently, Unity WebGL uses a custom Audio implementation, based on the Web Audio, which is different from all other Unity build platforms, which use FMOD. This allows us to handle basic playback of supported audio formats with volumes and pitch. Any audio functionality which can be implemented on top of this is expected to work (and we fix bugs when it does not) - anything more advanced is not.
We will not be able to change this until we have thread support in Unity WebGL (see the performance section), which might then allow us to compile the FMOD libraries to WebGL instead. That would get us close, but weâd also need APIs to set audio data from a worker, for which there is spec in Web Audio (âAudio Workersâ), but that is not implemented in any browser yet. So, while we expect to have audio feature parity at some point in the future, there is no ETA on this, as it would rely on future technologies, and it may well take a while.
Graphics
WebGL is a JavaScript API based on OpenGL ES 2.0. This is somewhat limiting graphical capabilities compared to other platforms, because OpenGL ES 2.0 does not support a lot of features we use on other platforms. Also, Unity currently has some hard-coded decisions which tie graphics functionality to graphics APIs, which have been appropriate in the past when OpenGL ES 2.0 was considered a âmobileâ graphics API, but with WebGL potentially running this code on higher end desktop GPUs, such assumptions may no longer hold up. This results in visual quality not being as good as it could be, especially when looking at shadows and the new standard shader. We have work in progress to fix this and make shader features configurable on a per-project base, instead of being hard-coded per graphics API.
Also, at GDC 2015, we showed a prototype of Unity 5 running on WebGL 2.0 (which is based on OpenGL ES 3.0), which will take WebGL graphics capabilities up one step. Unity 5.2 is planned to ship with experimental WebGL 2.0 support, but we donât expect browsers to actually support this API in release versions before the end of this year.
Browser support
Currently, Unity WebGL supports Chrome, Firefox and Safari. What is missing to get coverage of every major browser is support for Microsoft browsers. Current versions of Internet Explorer have WebGL support, but lack Web Audio support (so we cannot play any audio), and performance is not great, so while content may load, we do not currently officially support that.
We expect this to change with the release of Microsoft Edge, the upcoming new default browser in Windows 10 to replace IE. Edge will support Web Audio, and supports asm.js resulting in great performance for Unity content.
Video
Unityâs MovieTexture class is not currently supported in WebGL. It would be possible to get the video part to work, but there are no current plans to do that, as our MovieTexture audio playback could not work with the current audio solution on WebGL, and more importantly, it is easy to simply use the browserâs html5 video functionality to integrate a much more full-featured video texture solution into Unity WebGL.
Networking
Neither System.IO.Sockets.* nor UnityEngine.Network.* work with WebGL. Nor will they ever. This is due to security restrictions on the platform, which disallow direct access to IP sockets on the platform. However, it is possible to use the WWW class, or to integrate with Web Sockets or WebRTC using JavaScript, or you can use our new built-in multiplayer functionality Unity 5.1, which supports WebGL via Web Sockets out of the box. Or you can use third-party libraries like Photon or SmartFoxServer, both of which support Unity WebGL using WebSockets.
Threads
As mentioned in the performance section, we plan to support multi-threading for our internal engine code using Shared Array Buffers, once browsers ship support for that. We hope to eventually extend this support to user code using System.Threading.* as well, but that is a more difficult problem to solve, as Shared Array Buffers will not provide some functionality required by our GC. We have some thoughts on how to work around that, and expect to have a working solution eventually at some point in the future, but that will likely be at a later point in time after we have added multithreading support for Unity Engine code internally.