BabylonJS/Babylon.js · error
_readPixelsAsync only work on WebGL2+
Error message
_readPixelsAsync only work on WebGL2+
What it means
_readPixelsAsync relies on WebGL2's PIXEL_PACK_BUFFER and fence-sync readback, which do not exist in WebGL1. The engine guards on _webGLVersion < 2 and throws immediately rather than silently falling back.
Source
Thrown at packages/dev/core/src/Engines/engine.pure.ts:1027
return false;
}
return true;
},
resolve,
reject,
intervalms
);
});
}
/**
* This function might return null synchronously, so it is technically not async.
* @internal
*/
// eslint-disable-next-line no-restricted-syntax
public _readPixelsAsync(x: number, y: number, w: number, h: number, format: number, type: number, outputBuffer: ArrayBufferView): Nullable<Promise<ArrayBufferView>> {
if (this._webGLVersion < 2) {
throw new Error("_readPixelsAsync only work on WebGL2+");
}
const gl = <WebGL2RenderingContext>(this._gl as any);
const buf = gl.createBuffer();
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
gl.bufferData(gl.PIXEL_PACK_BUFFER, outputBuffer.byteLength, gl.STREAM_READ);
gl.readPixels(x, y, w, h, format, type, 0);
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
if (!sync) {
return null;
}
gl.flush();
// eslint-disable-next-line github/no-then
return this._clientWaitAsync(sync, 0, 10).then(() => {
View on GitHub (pinned to 0592b347b8)
Solutions
- Use the synchronous engine.readPixels() on WebGL1 instead of _readPixelsAsync.
- Ensure the runtime supports WebGL2 (update browser/headless flags: --enable-unsafe-swiftshader or use a GPU-enabled CI runner).
- Check engine.webGLVersion (or getCaps().textureFloatRender etc.) at startup and branch your code accordingly.
Example fix
// before
const data = await engine._readPixelsAsync(x, y, w, h, fmt, type, buf);
// after
if (engine.webGLVersion >= 2) {
const data = await engine._readPixelsAsync(x, y, w, h, fmt, type, buf);
} else {
engine.readPixels(x, y, w, h, buf);
} Defensive patterns
Strategy: validation
Validate before calling
if (engine.webGLVersion < 2) {
// use sync readPixels instead of _readPixelsAsync
} Type guard
function supportsAsyncReadback(e) {
return (e as { webGLVersion: number }).webGLVersion >= 2;
} Try / catch
try {
await engine._readPixelsAsync(x, y, w, h, fmt, type, buf);
} catch (e) {
if (/only work on WebGL2/.test(e.message)) {
engine.readPixels(x, y, w, h, buf);
}
} Prevention
- Check engine.webGLVersion at startup and record the capability set.
- Ensure target environments (CI, kiosk browsers) support WebGL2.
- Keep a WebGL1 fallback readback implementation.
When it happens
Trigger: Calling engine._readPixelsAsync(...) on an engine running WebGL1 (old browser, forced WebGL1 fallback, or a context created without WebGL2 support).
Common situations: Legacy Safari/iOS versions before WebGL2 support, running on a machine/driver where WebGL2 is unavailable so the engine silently falls back, headless environments (old headless Chrome) lacking WebGL2.
Related errors
- clientWaitSync failed
- Unable to create Transform Feedback
- Unable to create uniform buffer
- Multiview is not supported
- HDR prefiltering is not available in WebGL 1., you can use r
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/f916eab81c8f9660.
Report an issue: GitHub.