-
Notifications
You must be signed in to change notification settings - Fork 246
Build cesium-native for WebAssembly using Emscripten #1212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
If you want to do this the vcpkg way, you can use the VCPKG_CHAINLOAD_TOOLCHAIN_FILE variable to arrange for vcpkg to load another toolchain file after its own. Unfortunately, this toolchain file won't affect all the ports that vcpkg builds! To do this right you need to define a triplet for vcpkg that also loads the toolchain file... |
|
@timoore That makes sense! For some reason I'd assumed that does the opposite - use the toolchain for the ports and not for the rest of the CMake build. |
|
vcpkg already has a community supported wasm triplet, so you should be able to change the triplet and set the required environment vars to point to the emscripten sdk. |
|
@duckblaster It doesn't have a community-supported triplet that supports 64-bit wasm builds, as far as I can tell. But we are using a triplet to load Emscripten for vcpkg. The part that's tricky is loading Emscripten out of vcpkg, to use in the rest of the build. |
|
@azrogers ah, makes sense. |
|
Just showing interest. I would love to be able to use WebGL with Unity Cesium :D |
What is this?
We get a lot of requests for WebGL support in Unity. Unfortunately, that would require a WebAssembly build of Cesium Native, which we don't have. We have always put this task somewhere in the far future on account of it seeming like a huge amount of work, but after getting so many requests for WebGL at the Cesium Developer Conference last week, we thought it might be worth spending a few days testing it out to get an idea of how much work it would really be.
It turns out: not nearly as much as you might think!
This PR adds a fully working build of Cesium Native for WebAssembly using Emscripten. You can open up
build/CesiumNativeTests/cesium-native-tests.htmlin your web browser (usingnpm run test-wasmto spin up a web server with the correct HTTP headers for WASM threading) and see the entire test suite* run right there in the browser.But this does NOT mean we are ready to integrate with Unity WebGL. The primary problem is that we are using Wasm64**, and Unity seems to use Wasm32 (as it has much more support than Wasm64). Building for Wasm32 is theoretically possible, but Cesium Native has never been designed to build on anything other than a 64-bit architecture. Attempting to build for Wasm32 quickly fails on account of us assuming throughout the codebase that
sizeof(size_t) == 8.But I think this is a good proof-of-concept. A WebAssembly build to support Unity WebGL builds is entirely within the realm of possibility.
* The entire test suite, minus one test in CesiumGltfWriter which tries to allocate a >4GB buffer to see if the writer will reject it. In theory, since we're building for Wasm64, this should work, but it does not. But because this test isn't really testing any essential features, it doesn't seem worth the time to debug.
** I'd just like to interject for a moment. What you're referring to as Wasm64, is in fact, Wasm32/Memory64, or as I've recently taken to calling it, Wasm32 plus Memory64.
What did it cost?
Now that I've gotten all that preamble out of the way, here's a non-exhaustive list of some of the horrible hacks I had to perform to make CMake, vcpkg, and Emscripten happy with what I was trying to do:
CMAKE_SIZEOF_VOID_Pneeds to be manually overridden to8(as doesSIZEOF_SIZE_Tin the vcpkg triplet) because CMake can't tell that the-sMEMORY64=1parameter makes this a wasm64 build, not a wasm32 build.std::formatinstead offmt::formatbecause the latter was giving constexpr errors..html, because that will prompt Emscripten to generate a harness for running the built wasm and js in the browser. This breaks doctest, which tries to run the built binary to generate a list of tests for CTest and fails because it doesn't know how to possibly execute an HTML file.Besides that, everything was pretty straightforward! spdlog was the only library that required code changes, for whatever reason. There's also a bit of code in there to run the
file_packagerscript, which turns all of the test data on the file system into an object file we can link with the generated WebAssembly so the tests actually work.How do you use it?
It should be pretty simple! Just grab yourself a copy of the Emscripten SDK and run your CMake commands as normal, just prepending an
emcmaketo the configure call to set up the correct context. For example:Once it's built, you should be able to run the generated WebAssembly using either node (
node build/CesiumNativeTests/cesium-native-tests.js) or using your browser (either Chrome or Firefox, which support Memory64). When testing through the browser, you'll need to spin up a local server using thenpm run test-wasmcommand. This is because, to be able to access theSharedArrayBufferfor sharing memory between threads, the server needs to send the correctCross-Origin-Opener-PolicyandCross-Origin-Embedder-Policyheaders (read more here).