Question about attempt to use SharedArrayBuffer

In my ever going quest to improve performance (and keep memory flat), I started experimenting with SharedArrayBuffer(SAB) and having glb assets downloaded and pre-processed much as possible before being added into the buffer for Babylon to load.

For the first phase, I was just trying to get the glb binary data across and loaded by Babylon and further pre-processing in the worker would be a next step.

I got pretty far but running into one issue at the end that I have a question about. The steps I took so far:

  • Fork GLTFFileLoader, call it SABGLBLoader and register it as a plugin

  • Make a SAB and pass it to the plugin. Modify createPlugin to pass the SAB in.

  • Load a glb buffer in the worker and put it into SAB at appropriate offset

  • Return true from canDirectLoad

  • Trick SceneLoader.LoadAssetContainerAsync into using directLoad by passing data:sabglb for the rooturl.

  • SABGLBLoader directLoad passes the SAB into readAsync, offset needed and length

  • In _unpackBinaryV2Async JSON needs to be copied to new Buffer/TypedArray because Decode throws this:
    failed to execute 'decode' on 'textdecoder' the provided arraybufferview value must not be shared

Everything loads from there until I made it to the Blobs :confused: It’s a similar issue to using Decode on the json.
Failed to construct 'Blob': The provided ArrayBufferView value must not be shared.
( funfact there is exactly 1 google result for this error, in the webkit source/tests itself. This is either really dumb or pushing whats possible here haha)

Is this the end of this exact path for me or can anyone think of something different ?

I see I could possibly store then as base64 strings in the buffer and load that way instead ? I did not see a way I could hack that in without getting into BabylonJS code itself. I am not sure about if this would double memory for an asset or not either

cc @bghgary to see if already thought about it ?

2 Likes

Unfortunately, I don’t know a lot about SABs. I remember there were security issues with SABs before which I guess now have been mitigated.

That said, I’m not exactly sure what you are trying to do. Are you trying to do as much work as possible off of the main thread?

Unfortunately, I don’t know a lot about SABs. I remember there were security issues with SABs before which I guess now have been mitigated.

Yes I was learning about their crazy history. They are indeed back with the server headers needing to be included:

  res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
  res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');

That said, I’m not exactly sure what you are trying to do. Are you trying to do as much work as possible off of the main thread?

Yes, in particular downloading a glb and then decoding the images. I don’t think SAB is the only option for this, I would look into transferring individual array buffers next if SAB can’t be done. One large SAB interests me because of the fixed size. I have a feeling that for applications that load/unload massive amounts of data, iOSs memory sheriff called Jetsam will be much happier with this pattern. There is also a cost to using postMessage with Transfer that SAB does not incur if used correctly with Atomics

If it’s mostly about image decoding, then hopefully someday browsers will support offloading createImageBitmap on a different thread. See this old article: Chrome supports createImageBitmap() in Chrome 50 - Chrome Developers. That said, since we are already using createImageBitmap when it is available, we can consider adding support for doing this off the main thread explicitly, similar to what is mentioned at the end of the article.

That does sound nice about the image decoding.

The fixed size memory for assets is appealing as well though. Do you have any thoughts on the part I am stuck at now with SAB ? I think basically the question now is: Could decoded images be stored as base64 strings to be read from the SAB by Babylon. ( Since Blobs are not allowed to be used with SAB it turns out )

I don’t know, but base64 is not efficient at all, so I’m not sure why that would be good for performance.

Okay, I will do some more digging and profile the whole thing in detail for sure if do get it working