Source linked

One Chrome Flag Cut WebGL Screenshot Time 4× on GPU-Less Nodes

Microlink switched Chrome's ANGLE backend from SwiftShader to Mesa llvmpipe, dropping heavy 3D page renders from ~24s to ~6s on servers without GPUs.

microlinkchromewebglmesa llvmpipeswiftshaderheadless browsing

Microlink cut WebGL screenshot time from ~24 seconds to ~6 seconds on GPU-less nodes by flipping a single Chrome flag — a 4× speedup that turned a frequent timeout into a routine operation.

Why Headless Servers Hate WebGL

Microlink's browser fleet runs commodity Linux nodes with no graphics card: no /dev/dri, no hardware acceleration. Cheaper and simpler, until you ask it to screenshot a three.js page. WebGL is a GPU API, so without hardware, Chrome has to emulate it entirely on the CPU. That emulation path was the bottleneck.

Chrome delegates WebGL to ANGLE, which translates calls to whatever the platform supports: Direct3D, Metal, OpenGL, or a software renderer. On a GPU-less Linux box, ANGLE picks either its bundled SwiftShader or the system OpenGL stack — which in practice is Mesa's llvmpipe. Same pixels, wildly different cost.

Why llvmpipe Runs Circles Around SwiftShader

SwiftShader emulates the pipeline conservatively. It aims for "draws correctly anywhere" and pays for it: a heavy 3D scene takes ~24s, simple 2D pages 2-3s. Llvmpipe takes a different approach. It JIT-compiles shaders and GL state into real x86-64 via LLVM — no interpreter loop. It's tiled and multi-threaded, using every core. Result: same output, ~4× faster.

The change is one line: replace --use-angle=swiftshader with --use-angle=gl. But you must not add back --disable-gpu (silently forces SwiftShader) or --in-process-gpu (kills the GL surface). And you need a display: --use-angle=gl binds an X surface. Without one, WebGL silently degrades to flat 2D — screenshot succeeds, status 200, output wrong but plausible.

The Hidden Work: Display, Build, and CI

Every container boots Xvfb before Chrome starts, with LIBGL_ALWAYS_SOFTWARE=1 pinning Mesa to llvmpipe. Ubuntu jammy's Mesa is too old; official PPAs are gone. So Microlink builds Mesa from source in a multi-stage Docker image: meson setup build -Dbuildtype=release -Dgallium-drivers=llvmpipe -Dvulkan-drivers= -Dllvm=enabled -Dshared-llvm=enabled. That gives shared LLVM (the JIT) and only llvmpipe. The build toolchain is huge (LLVM, clang, Rust, ~160 -dev packages), but the final image is 2.65GB vs 4.5GB by copying only artifacts.

Proving it works requires a live GL context query, not apt list. Microlink's browserless.report() reads gpu.type (must be software), gpu.device (must be llvmpipe), and simdWidth (256 means AVX2 active). A benchmark: true option runs a deterministic shader in ~300ms. CI asserts these values — any drift fails the build, catching the flat-2D fallback before it ships.

Numbers That Mattered

Same 3D chart, same GPU-less hardware, measured on production:

Renderer Isolated Under Load
SwiftShader ~24s ~24s (timeouts)
Mesa llvmpipe ~6s 7–14s (all succeed)

The requests that used to time out now finish. Microlink now treats 3D screenshots as a standard capability, not a special-case fallback.


Source: WebGL Without a GPU
Domain: microlink.io

Read original source ->

External source stays available while the OJO article and comment thread stay local.

Comments load interactively on the live page.