BlinkGTK GPU Modes

BlinkGTK runs in one of three GPU modes, selected with the BLINKGTK_GPU_MODE environment variable.

About this page (updated 2026-08-16)
Parts of chapter 6 (troubleshooting) record symptoms observed on earlier
releases; some are resolved in the current release. Chapter 5 (switching)
is up to date. For the authoritative list of environment variables, see the
environment variables reference.


1. The three modes

Mode BLINKGTK_GPU_MODE Rendering Compositing Intended use
Software software (default) CPU Software compositor Headless, CI, servers, low-spec machines
SwiftShader swiftshader Software GL (ANGLE → Vulkan → SwiftShader) Software compositor Virtual machines, stability first
Native EGL egl Hardware GPU (Wayland EGL) GPU compositor Desktop, production

On-screen rendering

In the current release (BlinkGTK 1.2.3 / Chromium 154), the software and EGL modes
display Blink's rendering output in the GTK window.
Up to 1.2.3-build1 the
swiftshader mode showed nothing on screen (issue #151; the capture API also failed
because no frame arrived). This is fixed as of 1.2.3-build2: pages appear as in software
and EGL, and WebGL output is visible too. On 1.2.3-build1 and earlier, use software or EGL.

On machines without a usable GPU, asking for EGL falls back to software
automatically
(since v1.2.1-build2). It switches when no frame arrives within
five seconds and writes the reason to standard error; it does not switch where
the GPU path works. Set BLINKGTK_EGL_AUTO_FALLBACK=0 to disable it (the screen
may then stay white).

Resolved so far (history)

Version Item
v0.9 series --headless was forced onto the browser process, producing a white screen
v1.0.1 Issue #47 — EGL mode fix
v1.0.10 iter2–iter7 Issue #53 — SwiftShader mode fix
v1.0.10 iter5 Issue #54 — EGL mode viz Skia readback fix
v1.0.10 iter7 Issue #55 — EGL mode context-lost fix
v1.0.x (resolved 2026-04-20) Issue #58 — did not follow the parent container's size on HiDPI (fixed by implementing the size_allocate vfunc)
v1.1.x (resolved 2026-06-21) Issue #59 — repeated blink_web_view_load_uri() accumulated resources
since v1.2.0-build3 GPU rendering works with a single environment variable
since v1.2.1-build2 Automatic fallback on machines without a GPU

2. Mode details

2.1 Software (software)

Behavior:

Strengths:

Weaknesses:

Recommended for:

2.2 SwiftShader (swiftshader)

Behavior:

Strengths:

Weaknesses:

Recommended for:

2.3 Native EGL (egl)

Behavior:

On v1.2.0-build2 and earlier this shows a white screen.

The setup this path needs (GTK4 integration, manual viewport, device scale,
and the receiving widget) was left to the application, so nothing appeared
unless you knew to configure it. From the next release the engine does
this
, so BLINKGTK_GPU_MODE=egl alone is enough. On earlier versions,
please use software.

Falls back automatically on machines without a usable GPU:

You may select egl on a machine where the GPU path does not work (no driver,
no GPU visible inside a virtual machine, and so on). Previously the window
stayed blank with nothing to explain why.

Now, if no frame reaches the EGL path within five seconds, BlinkGTK switches to
the software path so drawing continues, and writes the reason to standard error.
The fallback does not trigger where the GPU path works. Disable it with
BLINKGTK_EGL_AUTO_FALLBACK=0 (the window then stays blank). See
Environment variables for details.

What it aims to provide:

Current limitations:

Current status:


3. Choosing a mode

What is the application's runtime environment?
├─ GPU + desktop + Wayland         -> egl
├─ No GPU, need WebGL              -> swiftshader
├─ No GPU, no WebGL                -> software (default)
└─ Headless / CI                   -> software or swiftshader

4. Launch examples

# Software mode (default)
./myapp --no-sandbox --no-zygote

# SwiftShader mode
BLINKGTK_GPU_MODE=swiftshader ./myapp --no-sandbox --no-zygote

# Native EGL mode
BLINKGTK_GPU_MODE=egl ./myapp --no-sandbox --no-zygote

Selecting the path from code (v1.2.2-build5 and later):

blink_gtk_set_gpu_mode(BLINK_GPU_MODE_EGL);   /* before blink_gtk_init */
blink_gtk_init(&argc, &argv);

Note: blink_web_view_new_with_gpu_mode() cannot select the path. The
rendering path is fixed at blink_gtk_init(), and so are the launch flags handed
to the GPU process. By the time a WebView is created it can no longer change, so
passing a mode there has no effect — it only emits a warning. (Found on
2026-09-14 from an external report; until then it was possible to measure the
software path while believing EGL was in use.)

There is one path per process. It cannot differ between WebViews in the same
process.

Confirm what took effect with blink_web_view_get_gpu_mode(); the startup log
also prints the path. Setting BLINKGTK_GPU_MODE before launch still works.


5. Switching modes and paths — what can change at runtime

There are two different axes, with different capabilities.

Axis Example Switchable at runtime?
GPU mode (software / swiftshader / egl on this page) software → egl No — requires a process restart
Delivery path (how frames reach the screen) P1 (direct) ↔︎ P2 (mojo shared memory) ↔︎ P3 (EGL dmabuf) Yes (P1↔︎P2 since v1.2.0-build9, P3 since v1.2.1-build3) — blink_web_view_switch_render_path()

5.1 Switching the GPU mode (restart required)

If your application offers a UI (for example a menu item) that lets the user
pick a GPU mode, changing the mode requires restarting the process.

// When the user selects a different mode
g_setenv("BLINKGTK_GPU_MODE", "egl", TRUE);
execv(argv[0], argv);  // restart the process

To carry state (URL, scroll position, display scale) across the restart, use
the handoff meta API (blink_web_view_export_handoff_meta() /
import_handoff_meta()). It carries the display scale in canonical units, so
the restarted view does not come back undersized.

5.2 Live delivery-path switching

There is more than one delivery path (P1 = direct, P2 = mojo shared memory,
P3 = EGL dmabuf), and these can be switched without a restart:

int seq = blink_web_view_switch_render_path(view, "P2");
/* Completion arrives on the "render-path-changed" signal. If the new path
 * fails its render check, the previous path is restored automatically
 * (result="rollback" — the screen is never broken). */

A switch takes a few hundred milliseconds in our test environment. See the
render-path-changed section of the
Signals API reference for details
(sequence numbers, result values).

Scope: this API switches software-side delivery paths ("P1" / "P2") only.
It does not switch the GPU mode itself (software ↔︎ egl) — use the restart
procedure in 5.1 for that.

5.3 Stopping presentation instead (presentation policy)

If what you actually want is "this view need not be presented right now"
(an audio-only mode, for example) rather than a different path, the proper
tool is the presentation policy:
blink_web_view_set_presentation_policy(). It skips only the cost of
presenting frames; layout and rasterization (read-ahead) continue.
While presentation is stopped, a screenshot request (blink_web_view_capture_screenshot_async()
and similar) still gets exactly one frame, after which presentation stays stopped (1.2.3-build2 and later).


6. Troubleshooting

6.1 FATAL: gl_factory_ozone NOTREACHED in EGL mode

Cause: the Wayland EGL driver is not found, or the process is falling back to an X11 display.
Fix: use v1.0.10 iter7 or later (fixed for v1.0.1 in
Issue #47, hardened further for v1.0.10 iter7 in
Issue #53).

6.2 VK_ERROR_INITIALIZATION_FAILED in SwiftShader mode

Cause: ANGLE's Vulkan backend fails to initialize against the environment's Vulkan driver
configuration.
Fix: use v1.0.10 iter7 or later. In iter7 the SwiftShader path was changed to explicitly avoid
ANGLE Vulkan (Issue #53). Upgrade if you are on
iter6 or earlier.

6.3 SwiftShader renders, but pixels never reach GTK

This is resolved as of 1.2.3-build2 (first fixed on 2026-04-19 under Issue #54;
it came back in later versions, issue #151).

6.4 EGL rendering is clipped to the top-left corner (HiDPI)

This is resolved (Issue #58, 2026-04-20).

6.5 White screen in every mode

This can still occur under some conditions even on v1.0.10 iter7 and later. Check the following:

See Troubleshooting for details.


7. Benchmarking

The triple_gpu_compare sample (examples/triple_gpu_compare.c) compares all three modes side by side
within a single application.

Running from a Chromium build tree:

cd $CHROMIUM_SRC/out/Release_Component
LD_LIBRARY_PATH=$PWD ./triple_gpu_compare

When installed from a tarball or RPM:

# The executable lives in $prefix/bin; runtime .so files in $prefix/lib/chromium
cd /usr/local/lib/chromium   # or adjust to your prefix
/usr/local/bin/triple_gpu_compare

Three WebViews are displayed side by side so you can compare FPS and rendering quality.