WASM memory access out of bounds using DracoLoader on Mobile Browsers

Hi,

I’m currently running into an issue where I’m trying to load a Draco compressed model using the Draco Loader on mobile browsers and it seems to hard crash during the call to the .load method. iOS Safari not and Chrome version 88.0.4324.93 on an Android - Pixel 2 XL are the ones I’ve tested so far. The exact same models seem to render completely fine on web browsers with no issues.

This the error I’m receiving

RuntimeError: memory access out of bounds
at <anonymous>:wasm-function[377]:0x18a28
at <anonymous>:wasm-function[358]:0x170b9
at <anonymous>:wasm-function[354]:0x16f17
at <anonymous>:wasm-function[446]:0x21f40
at <anonymous>:wasm-function[323]:0x1371f
at <anonymous>:wasm-function[23]:0x2cb1
at emscripten_bind_Decoder_DecodeBufferToMesh_2 (<anonymous>:wasm-function[119]:0x934e)
at a._emscripten_bind_Decoder_DecodeBufferToMesh_2 (blob:https://bdd35c37d00a.ngrok.io/95a82b20-81cc-451e-a630-f47694de7a0f:51:560)
at g.DecodeBufferToMesh.g.DecodeBufferToMesh (blob:https://bdd35c37d00a.ngrok.io/95a82b20-81cc-451e-a630-f47694de7a0f:92:54)
at decodeGeometry (blob:https://bdd35c37d00a.ngrok.io/95a82b20-81cc-451e-a630-f47694de7a0f:189:29)

I’ve tried adding console logs to the onProgress, onLoad, and onError callbacks. The onProgress seems to fully complete but after that, before the onLoad callback can run, it crashes and the onError callback isn’t called either.

Anyone have any ideas on how to go about solving this? Any help would be much appreciated.

Max memory usage is variable across browsers, and lower on mobile. Anyway it seems that your model is too big. How heavy is it ?

I thought this might be an issue as well but the model itself is only about 100 mb. The JS heap snapshot is ~363 mb after loading on web and the snapshot on my mobile device using the chrome debugger is 193 mb (but probably lower because the model doesn’t fully load is my guess)

Is the model 100mb before Draco compression, or after? Any chance you’d be able to share it?

Or, are you able to see the issue on these mobile devices with this example? three.js examples

Sorry, I was actually misinformed. The draco size after compression is 50.9MB. And yes I can share the model. Did you want a link to the implementation or the model itself?

The models seem to work completely fine in those examples.

Either one!

Draco compression rates can be as good as 95%… if the 50MB is expanding to 50 / .05 = 1000MB during decompression then you may just be running out of memory on these devices. If that’s the issue then you may need to simplify the models before compressing them, or there are other types of compression you could try.

This is the implementation VRIFY | See for yourself. and this is the model itself https://cdn.vrify.com/shelf/companies/1116/files/39950f59-3bf1-42cc-a806-65358d4f4701.glb

Ohhhh, that’s really interesting. This is probably going to be a stupid question but in terms of the file size, when I take the heap snapshot in the Memory tab of the Chrome DevTools, does the size of the uncompressed model not get reflected there? Like for example, in the first link, after the model loads, and I take the heap snapshot, the size is 363 mb so would that be enough to cause the device to run out of memory?

Note that both Draco geometry and PNG/JPG textures have to be decompressed when rendering to the GPU. The full size of the textures and geometry, after decompression, in this scene is about 930 MB. That’s roughly 190 MB of geometry and 740 MB of textures. Some of the textures have dimensions like 5819 x 4480px, which is too large for many mobile devices. I would not expect mobile devices to support anything larger than 4096px, and ideally avoid using more than 2048px.

I can’t tell you exactly which of these things is causing the crash you’re seeing, but generally it does seem like this model will need to be simplified, by an artist or with software like Blender or RapidCompact.

Here are the textures’ stats, produced with gltf-transform inspect model.glb:

# name uri slots instances mimeType resolution size memSize
0 baseColorTexture, occlusionTexture 2 image/png 3157x2427 676.9 KB 29.23 MB
1 baseColorTexture, occlusionTexture 2 image/png 3157x2427 714.15 KB 29.23 MB
2 baseColorTexture, occlusionTexture 2 image/png 3157x2427 739.2 KB 29.23 MB
3 baseColorTexture, occlusionTexture 2 image/png 3106x2371 1.62 MB 28.09 MB
4 baseColorTexture, occlusionTexture 2 image/png 3106x2371 1.78 MB 28.09 MB
5 baseColorTexture, occlusionTexture 2 image/png 3106x2371 1.75 MB 28.09 MB
6 baseColorTexture, occlusionTexture 2 image/png 3106x2371 1.22 MB 28.09 MB
7 baseColorTexture, occlusionTexture 2 image/png 3106x2371 1.47 MB 28.09 MB
8 baseColorTexture, occlusionTexture 2 image/png 5819x4480 624.62 KB 99.45 MB
9 baseColorTexture, occlusionTexture 2 image/png 5819x4480 600.27 KB 99.45 MB
10 baseColorTexture, occlusionTexture 2 image/png 5819x4480 663.42 KB 99.45 MB
11 baseColorTexture, occlusionTexture 2 image/png 2189x1692 228.28 KB 14.13 MB
12 baseColorTexture, occlusionTexture 2 image/png 2189x1692 238.82 KB 14.13 MB
13 baseColorTexture, occlusionTexture 2 image/png 2189x1692 269.41 KB 14.13 MB
14 baseColorTexture, occlusionTexture 2 image/png 1012x675 1.51 MB 2.61 MB
15 baseColorTexture, occlusionTexture 2 image/png 1013x675 1.22 MB 2.61 MB
16 baseColorTexture, occlusionTexture 2 image/png 869x414 21.39 KB 1.37 MB
17 baseColorTexture, occlusionTexture 2 image/png 583x1140 39.45 KB 2.54 MB
18 baseColorTexture, occlusionTexture 2 image/png 2048x3165 1.46 MB 24.73 MB
19 baseColorTexture, occlusionTexture 2 image/png 882x1408 158.92 KB 4.74 MB
20 baseColorTexture, occlusionTexture 2 image/png 1128x2260 272.04 KB 9.72 MB
21 baseColorTexture, occlusionTexture 2 image/png 899x1876 152.75 KB 6.43 MB
22 baseColorTexture, occlusionTexture 2 image/png 583x546 16.17 KB 1.21 MB
23 baseColorTexture, occlusionTexture 2 image/png 1115x2026 1.29 MB 8.62 MB
24 baseColorTexture, occlusionTexture 2 image/png 1064x2045 173.73 KB 8.3 MB
25 baseColorTexture, occlusionTexture 2 image/png 891x2331 96.14 KB 7.92 MB
26 baseColorTexture, occlusionTexture 2 image/png 2304x3240 234.66 KB 28.48 MB
27 baseColorTexture, occlusionTexture 2 image/png 1792x3047 12.63 MB 20.83 MB
28 baseColorTexture, occlusionTexture 2 image/png 1128x2260 96.5 KB 9.72 MB
1 Like

Additionally, you may find this useful as it will give you the maximum size of texture supported on a given device.

renderer.capabilities.maxTextureSize / 4;
1 Like

That is unbelievably helpful. Thank you so much, I’m definitely going to take a look at reducing the size of some of these models and will look into implementing gltf-transform to be able to get a breakdown like this for future issues.

Much appreciated!

Hey Don,

I tried reducing the size of the textures which seemed to drop the size of the .glb from the previous 50mb to ~37mb which is here https://dev-cdn.vrify.com/shelf/companies/1251/files/49ca3d71-aec1-46ac-be08-129bb62998a8.glb

However, I seemed to briefly get this error instead of the old one

blob:https://dev.vrify.com/d96ae97a-72fb-422a-8201-5b2dff8ee537:124 Error: THREE.DRACOLoader: Decoding failed: 
    at blob:https://dev.vrify.com/d96ae97a-72fb-422a-8201-5b2dff8ee537:124
    at blob:https://dev.vrify.com/d96ae97a-72fb-422a-8201-5b2dff8ee537:124
(anonymous) @ blob:https://dev.vrify.com/d96ae97a-72fb-422a-8201-5b2dff8ee537:124
9544:1 Uncaught (in promise) Object

But since then, I’ve continued to receive the old error about the memory access being out of bounds. Does this mean that the model’s textures are still too big or does the new error indicate something could be going wrong during the creation of the model/draco compression of the model? (I’m in the process of going about implementing the gltf-transform but just a bit slow)

Thanks again for any help/input you can provide.

edit:

I think I figured out the issue. One of the geometry’s in the model was gigantic and was causing problems when it was being uncompressed. I created a version of the model with only that material + another, leaving the draco model at 21MB and it still failed and upon further investigation, it was just way too detailed so we’ll look to reducing the complexity/size of it. Thanks for the help everyone!

1 Like

Could you please explain why you divide by 4?
Doc says:

- maxTextureSize: The value of **gl.MAX_TEXTURE_SIZE** . Maximum height * width of a texture that a shader use.

This leads me to think you need a square root. So for example my pc gives me renderer.capabilities.maxTextureSize = 16384. Does that mean the texture should be smaller than 128x128?

I seem to be hitting this issue as well on mobile. The scene loads about 80% of the time, but 20% I get this error message. I’m loading three small glb files. After compression they are about 2mb total, before compression about 25mb.

Related: Unsafe to reuse a Decoder instance · Issue #656 · google/draco · GitHub

@donmccurdy you mentioned on GH:

After changing my code to create a new Decoder instance for each mesh, the error was resolved.

Do you mean creating a new Decoder for each mesh primitive inside a single .glb file? Do you still have the code you used to do this?

That comment was referring to the Draco decoder implementation in glTF-Transform, which can be found here:

I haven’t modified THREE.DRACOLoader recently, but it seems to do the same:

… so I don’t think the error you’re seeing is likely to be exactly the same thing. I’d be curious if the error becomes more common with higher or lower parallelism? For example, calling dracoLoader.setWorkerLimit(1) or dracoLoader.setWorkerLimit(1000). That might indicate something or other. It’s also possible to compile debug builds of Draco which may have better error messages.

I’ve tracked this down to one of the four files I’m loading. The error only occurs when I load the draco version of the file, even when I’m loading other draco compressed files.

The file is called buildings.glb. It’s 7.8mb uncompressed, 1.07mb compressed. It’s originally an FBX file that I exported from Max then converted with FBX2GLTF.

It only causes this error when I used gltf-transform to compress the file. If I use FBX2GLTF to directly output draco compressed .glb, it’s fine, and if I use gltf-pipeline to compress it, it’s also fine:

  1. This causes the error
FBX2GLTF -i buildings.fbx -b
gltf-transform draco buildings.glb buildings.draco.glb
  1. This does not cause the error (-d flag applies draco compression). The compressed file is larger though (>2mb):
FBX2GLTF -i buildings.fbx -b -d
  1. This also does not cause the error, and has the smallest file size (1.04mb).
FBX2GLTF -i buildings.fbx -b
gltf-pipeline -i buildings.glb -o buildings.draco.glb -d --dracoCompressionLevel 10

EDIT: just realised gltf-pipeline messes up the UVs so that’s not an option either.

When I set worker limit to 1, I get the same error. When I set it to 1000, I get Uncaught (in promise) RangeError: WebAssembly.Memory(): could not allocate memory repeated many times.

If you like, I can share the file privately with you.

Hm, I’m not sure why glTF-Transform output would produce files that inconsistently cause OOB errors in Draco… is that a glTF-Transform bug or a bug in a Draco decoder? But I’d be happy to look into it more if you can share the file privately.

Once I had pinned down the file causing the error, it was consistent. I was testing out compression on several models and it was only happening on mobile so I mistakenly thought it was only happening occasionally.

Sorry for the delay in getting back to you. I reached out to the client and they don’t want me to share the model with anyone, even in private :confused:

In any case, I went with gltfpack with the -cc option which gives pretty good compression (1.7mb vs 1.07mb with draco).

Ah ok, understood! If someone does find a model they can share reproducing the issue I’m happy to look into it.

One quick tip – gltfpack compression benefits disproportionately (by design) from Gzip, so it’s helpful to compare against Draco with Gzip applied to both files.

1 Like

Good to know, thanks :slight_smile:

@donmccurdy I encounter the same problem in Android chrome browser. I am using GLTF-pipeline to compress the file. It loads fine in desktop and even in Android mobile native browser, Firefox mobile and add all the browsers in Iphone. It doesn’t work only on Android Chrome browser.
I am attaching the GLB file which runs in to a problem.

maltida.glb (2.5 MB)

1 Like