Pulse Engine on WebGL (Unity build)

Has anyone had success running Pulse Engine in a WebGL build (Unity), or otherwise running in a web application?

I have taken a stab at this several times, but I keep getting stuck and not knowing what to do

I first cross compile Pulse with emscripten via this dockcross container. This produces static libraries that I believe are what Unity wants.

I don’t see anything in the Unity documentation, but I believe that since these are static libraries, I have to mark the Pulse C# to Native C++ class with Internal when building for a WebGL platorm. So I changed that line to

public class PulseUnityEngine : PulseEngineBase
{
  #if UNITY_IOS || UNITY_WEBGL_API
    private const string Attribute = "__Internal";
  #else
    private const string Attribute = "PulseC";
  #endif

This is how we get iOS build support. For iOS, I also provide static libraries.

So, now when I build the Pulse VitalsMonitor scene for WebGL, the build seems to be running emscripten on the Pulse static libraries built from the docker contatiner.

But the build soon fails with

Building Library\Bee\artifacts\WebGL\build\debug_WebGL_wasm\build.js failed with output:
wasm-ld: warning: function signature mismatch: PulseHash
>>> defined as (i32) -> f64 in C:\\Users\\AARON~1.BRA\\AppData\\Local\\Temp\\tmpk80puxihGameAssembly.a(bizftqft4zrn.o)
>>> defined as (i32) -> void in C:\\Users\\AARON~1.BRA\\AppData\\Local\\Temp\\tmp9x6dm5f6PulseC.a(PulseEngineC.cpp.o)
[parse exception: attempted pop from empty stack / beyond block start boundary at 26994213 (at 0:26994213)]
Fatal: error in parsing input
emcc2: error: '"C:/Program Files/Unity/Hub/Editor/2021.3.30f1/Editor/Data/PlaybackEngines/WebGLSupport/BuildTools/Emscripten/binaryen\bin\wasm-emscripten-finalize" --minimize-wasm-changes -g Library/Bee/artifacts/WebGL/build/debug_WebGL_wasm/build.wasm -o Library/Bee/artifacts/WebGL/build/debug_WebGL_wasm/build.wasm --detect-features' failed (1)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

It did this for a few other methods, and I just commented those methods out
I am not sure what this error is trying to tell me, and what is wrong with that method.
The method in question is:

extern "C"
C_EXPORT void C_CALL PulseHash(char** hash_str)
{
  std::string hash = PulseBuildInformation::Hash();
  *hash_str = c_strdup(hash.c_str(), hash.length());
}

Which is called from PulseUnityEngine.cs

  [DllImport(Attribute)]
  private static extern double PulseHash(out IntPtr version_str);

Which is not getting a double back…

Maybe I just need to clean up my interfaces…
type type type
Ok, I changed the PulseUnityEngine::PulseHash return to be void
And that got rid of that one error, but there is still other mysterious errors

I guess the next thing too google is that parse exception…

I think its becauase dockcross is on emscripen 3, and unity is using emscripten 2…

Awesome response - Thanks Aaron. I am definitely not worthy on getting this working on my own, but great base for conversation with Kitware tuesday.

Hi Abray,
I’m trying to run it on WEBGL using Unity 6. Unity 6 uses emscripten 3+. Can you provide the compiled files for WEBGL that I can try to run my WEBGL on?
Thanks

Here is a wasm build of Pulse 4.3.2

It should be built with against wasm 4.0.3

Thanks for sharing the files Abray. I was able to build these myself as well. And I also got stuck on the same error you were stuck last time (Stack out of bounds issue). Screenshot attached:

Do you happen to resolve this issue? I searched about it a lot and was able to find that it could be due to struct type mismatch in cpp code. The pulse engine is big enough and I cannot go through it on my own to review all the code.

My reference for the above conclusion is this thread: Unity webgl build error: [parse exception: attempted pop from empty stack / beyond block start boundary] · Issue #21895 · emscripten-core/emscripten · GitHub

Do you have any thoughts on how to solve this? This asset is only usable for us if we can support for iOS, android and WEBGL.

I am not confident that the dockcross version is compatible with what Unity is expecting.
That would the first thing I would investigate.

With that figured out, I would write a super simple C++ library with one function in it, such as sum(float, float) that just adds two numbers together, and see if I could get that into unity using the dockcross build process.

If you can get that figured out, knowing that process was correct, we could turn to compiling the Pulse library to see if we get the same errors.

So I was finally able to solve this issue. And made it work on WebGL.

Process:
So I installed the emsdk first with version closer to unity’s version (Unity uses 3.1.39). I installed 3.1.25 but I believe it will work normally with dockcross as well. With dockcross, there was 1 extra error, related to some emscripten version not found. I fixed that by creating a stub cpp class and putting the function definition there and creating the .a file for that cpp.

So, with the emcc, I made the build for web, used the compiled protobuf data from linux based build as you do with dockcross, and was able to build the files.

Then after putting the files in unity and trying to build, I got the same error as before (attemtped pop from empty stack). It was frustrating but I decided to dig deeper.

Unity Error:
[parse exception: attempted pop from empty stack / beyond block start boundary at 57045490 (at 0:57045490)]
Fatal: error in parsing input

With some help from GPT, I was able to get my built WASM file with this error and disassembled it with wasm-objdump. From there, I got the hex address based call stacks. Converted the line address from Unity error to hex-address(36671F2) and searched in the file. Where I found this code block:

According to this, there is nothing on the code block that unity was trying to access(36671F2) which was the issue. So I went to find the functions in the code block (Unity Engine PulseVersion).

Got that in PulseEngine.cpp and turns out there was a mismatch. As you see in screenshot, the cpp is returning void. Whereas the c# implementation below is expecting a double in return type.
So the fix was just to change the return type in unity to void to match the mapping and voila, it worked flawless.

Oh wow!!
Excellent work!!!

It also looks like the PulseHash specification in C# also has that error.
I will get that fixed and pushed into the code base!

Thanks for digging into this issue!

Does it still run at about the same speed as desktop builds?
I have no idea if this would slow down Pulse…

So far, I don’t see any difference in the speed. It’s working well. Will share any observations after testing for a few days.

Also, it would be good if you can put the compiled version of webgl plugins in the codebase as well like iOS.

Does the wasm library I built earlier this week work in your project now that you fixed the C# side?

Awesome troubleshooting. Can’t wait to try this out in Unity WebGL once it makes it into the Pulse build.

No, it needs to be built specifically for the Unity version you are supposed to used with the supported emscripten version used by unity.

Ok

I can build a dockcross container with a specific version and test it out

This seems to be the wasm version list per unity build

So I have been building the Pulse Asset with 2021.3
It seems like I should bump the minimum build up to 2022.2 so I can build Pulse with wasm 3.1.8 and hopefully that will work in any Unity version after 2022.2
(Let me know if anyone uses a version previous to 2022.2)

Hopefully building against the off the shelf version dockcross is pulling works…

Will keep you all posted

1 Like

@ihamza301 Did you build static or a dynamic PulseC library?

I have a dockcross container with 3.1.38, and so far no build exception, but the application is unable to load the binary. I assume I need to switch everything to static… working on that now

If we do need static, did you have to modify this with a webgl macro?

@abray I built static libraries. And yes I had to add the webgl macro along with ios as well in a couple of files.

Thanks for helping out with this.

I got it all working using Unity 2023.2 using emscripten 3.1.39 built by dockcross
@ihamza301 What version of Unity are you using?

I am going to try to get this working in 2022.3
So far the linker does not like the 3.1.39 version of the libraries

It looks like WebGL is highly sensitive to the emscripten version used, and each editor version tends to require Pulse be built with a different version

So I don’t know how deployable it is from a store asset perspective… I might just need to build versions as people request them and stick them in our repo, bundling a bunch of native builds may get out of hand…

Originally, I used Unity 6 version where emscripten 3.1.39 works. Unity uses 3.1.39 for all versions above 2023.2 so I guess that should work with all above.

My requirements changed to use Unity 2022.3 so I had to recompile the files using emscripten 3.1.8 as Unity 2022.2 uses that version.

So for distribution, I believe you can just distribute the 3.1.39 version as current supported and provide a detailed readme if anyone wants to build it for any other version.

Or maybe build it for both and just keep them in repo and they can download per their requirements from here.

Thanks!

Yeah, I got it working for both 2023 and 2022

I put both of those builds in an appropriately named folder in the repo

Since Unity is generally forward compatible, I build an asset for the oldest version I want to support. This will be the 2022 version of Unity. So I will have the meta files in the 3.1.10 folder be associated with webgl and the 3.1.39 will not be associated with any platform.

2023 user can just unselect the platform associated with the 3.1.10 files and associate webgl with the 3.1.39 files

So this is working well for 2022 and 2023 unity editors

I will also push up some improvements and commenting to the xcompile/dockcross scripts in the engine repo.