Symbol-layer UBO allocation crashes WebGL context on mid-range mobile GPUs (Pixel 8a / Mali-G715) — regression in 3.21
bug :lady_beetle:
### mapbox-gl-js version
3.21.0 (also 3.22.x). Works correctly in 3.19.1.
### Browser and version
Chrome 141.0.7390.x on Android 15 (Pixel 8a, Mali-G715 MP7).
### Expected behavior
A map using mapbox://styles/mapbox/streets-v12 should render on a current-generation mid-range mobile GPU (Pixel 8a) without exhausting the WebGL UBO budget. Ideally either:
(a) UBO allocations chunk across draw calls so they fit within the device's GL_MAX_UNIFORM_BLOCK_SIZE / GL_MAX_UNIFORM_BUFFER_BINDINGS limits, or
(b) a config option (e.g. Map#setUseUBO(false)) allows apps to opt back into the pre-3.21 attribute-based symbol path on constrained hardware.
### Actual behavior
Tab hard-crashes ("Aw, Snap!") within ~2 seconds of first paint. The WebGL context is lost and Chrome kills the renderer. All symbol layers in the style are affected — the crash is triggered by the populateUBO call path added in 3.21.
Before the crash, "Image 'X' could not be loaded" warnings appear for any custom symbol icon, because addImage callbacks never resolve —
they are pre-empted by the UBO allocation failure on the same frame.
The 3.21.0 changelog identifies the relevant change:
- Improve symbol layer rendering performance (by adopting Uniform Buffer Objects for data-driven properties).
Downgrading to 3.19.1 resolves the crash with no other code changes.
### Link to the demonstration
https://jsbin.com/fupadolaxi/edit?html,output
### Steps to trigger the unexpected behavior
1. Open the JSBin link above on a Pixel 8a (or any mid-range Android with a Mali-G715).
2. Observe map painting for ~1-2 seconds.
3. Tab crashes with "Aw, Snap!"
To confirm the regression is in 3.21: edit the JSBin, replace both occurrences of "v3.21.0" with "v3.19.1", save, and reload on the same device — the map renders and stays rendered.
Desktop browsers (Chrome / Firefox / Safari on Mac or Linux) do not reproduce the crash because desktop GPUs have a far larger UBO budget.
### Relevant log output
```shell
RangeError: Array buffer allocation failed
at new Float32Array
at Ig.populateUBO
at hb.addSymbols
WebGL: INVALID_OPERATION: useProgram: program not valid
WebGL: INVALID_OPERATION: getUniformLocation: program not
linked
WebGL: INVALID_OPERATION: getAttribLocation: program not linked
WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost
WebGL: INVALID_OPERATION: delete: object does not belong to
this context
WebGL: INVALID_OPERATION: deleteVertexArray: object does not
belong to this context
WebGL: too many errors, no more errors will be reported to the
console for this context.
Image "pin-inactive" could not be loaded. Please make sure you
have added the image
with map.addImage() or a "sprite" property in your style. You
can provide missing
images by listening for the "styleimagemissing" map event.
```
关闭于 2026-05-06 7 条评论