Figma's Config 2026 shader fills (dithering, blur, frosted glass, fractal noise, liquid metal) run on WebGPU. They render fine in Chrome on Linux. Wrap the same Figma in Electron on Linux + AMD, and they silently don't show up.
I chased this on an AMD Radeon 780M (Mesa RADV, Wayland/GNOME) for a self-hosted Electron Figma client. The fix turned out to be the opposite of what every "enable Skia Graphite" thread suggests. Here's the whole journey, with a reproducible probe harness.
TLDR Don't enable Skia Graphite. Use
--ozone-platform=x11 --ignore-gpu-blocklist --enable-unsafe-webgpu(no--enable-skia-graphite). That keeps the fast GaneshGL raster backend while turning onwebgpu_on_vk_via_gl_interop, which is what actually lets the shaders run — and without the canvas lag Graphite introduces. And apply those switches beforeapp.ready, or Chromium ignores them.
The wrong assumption: "you need Skia Graphite"
The intuitive theory: Figma's WGSL shaders need Chromium's new Skia Graphite backend (Dawn → Vulkan), and release Electron keeps Skia on the old Ganesh-GL path, so shaders can't reach the GPU.
So I built a probe — a bare Electron BrowserWindow that renders a WebGL triangle + a WebGPU clear pass, then dumps app.getGPUFeatureStatus(), getGPUInfo(), the WebGL renderer string, and the WebGPU adapter — and ran it across a flag matrix on multiple Electron versions. (Harness + raw dumps in the gist: [LINK TO GIST].)
First gotcha: getGPUFeatureStatus() reports "everything software/off" if you read it at whenReady — the GPU process hasn't reported yet. Read it after the window has actually rendered.
Second gotcha — switch vs. feature: --enable-features=SkiaGraphite hits a guard:
gpu/config/gpu_finch_features.cc:650]
Enabling Graphite on a not-yet-supported platform is disallowed for safety
That guard is about Wayland ozone, not Linux in general. The dedicated switch --enable-skia-graphite bypasses it, and you need X11 ozone. Minimal recipe that actually flips Graphite on (verified against real Chromium 149 → Skia Backend: GraphiteDawnVulkan):
electron --ozone-platform=x11 --enable-skia-graphite
It worked. chrome://gpu showed Skia Backend: GraphiteDawnVulkan. Victory?
The catch: Graphite is slow here
With Graphite on, panning the canvas lagged. Noticeably. And the same flags in raw Chromium lagged identically — so it's not an Electron artifact, it's GraphiteDawnVulkan on an integrated GPU + Mesa being heavy for this workload.
So I had working shaders but worse performance. Toggling it off restored speed but killed the shaders. Dead end — until an accident.
The accident: a third, better state
I turned the in-app toggle off, the app asked to restart, I clicked restart — and the shaders kept working, with the good performance back. chrome://gpu said Skia Backend: GaneshGL (Graphite off!) but WebGPU interop: Hardware accelerated.
Then I fully quit and cold-started — shaders gone, interop off again.
I saved all three chrome://gpu dumps. The Command Line field (chrome://gpu prints the real process argv) told the story:
| State | ozone | skia-graphite | ignore-blocklist | unsafe-webgpu | Skia Backend | interop | shaders | perf |
|---|---|---|---|---|---|---|---|---|
| 1 toggle ON | x11 | yes | yes | yes | GraphiteDawnVulkan | off | ✅ | 🐢 lag |
| 2 toggle OFF + in-app restart | x11 | no | yes | yes | GaneshGL | on | ✅ | ⚡ fast |
| 3 toggle OFF + cold start | wayland | no | no | no | GaneshGL | off | ❌ | fast |
State 2 is the sweet spot: GaneshGL (fast) + webgpu_on_vk_via_gl_interop (shaders work). It appeared by accident because app.relaunch() re-launches with the previous process's argv (note the --ozone-platform=x11 that showed up duplicated), carrying the unlocked-GPU flags forward — but the now-toggled-off code path didn't re-add --enable-skia-graphite.
Pinning down the real recipe
Back to the probe to bisect what controls webgpu_on_vk_via_gl_interop:
| flags | backend | interop | webgpu adapter |
|---|---|---|---|
x11 + ignore-blocklist + unsafe-webgpu |
GaneshGL | on | ✅ deviceOk |
+ enable-skia-graphite |
Graphite | off | ✅ |
x11 + unsafe-webgpu (no blocklist bypass) |
GaneshGL | off | ✅ |
x11 + ignore-blocklist (no unsafe-webgpu) |
GaneshGL | on | ❌ no adapter |
So:
-
--ignore-gpu-blocklistis required to flip interop on. -
--enable-unsafe-webgpuis required to get a real WebGPU adapter (the shaders' device). -
--enable-skia-graphiteis harmful — it switches to the slow Graphite backend and turns interop off.
The recipe:
electron --ozone-platform=x11 --ignore-gpu-blocklist --enable-unsafe-webgpu
→ Skia Backend: GaneshGL, webgpu_on_vk_via_gl_interop: enabled, a real hardware WebGPU device (AMD RDNA-3, shader-f16/subgroups), fast canvas, working shaders, zero warnings.
It works on native Wayland too, but Wayland + ignore-gpu-blocklist enables Vulkan compositing, which logs '--ozone-platform=wayland' is not compatible with Vulkan and risks instability. X11 (under XWayland) is clean — the only cost is losing native Wayland niceties (fractional scaling, per-monitor DPI).
Side note on Chromium's issue 442791440:
webgpu_on_vk_via_gl_interopis listed as a disabled feature by default for AMD+Mesa, but in practice it flips to "Hardware accelerated" once the blocklist is bypassed and Graphite isn't forced. Useful data point if you're tracking that bug.
The bug that made it all flaky: switches applied too late
Why did the recipe only work after an accidental app.relaunch(), never on a clean start? Because app.commandLine.appendSwitch(...) only takes effect if it runs synchronously, before app.ready. The main process did:
async function start() {
await storage.initialize(); // app.ready fires during this await
...
new App(); // ← appendSwitch('ozone-platform','x11'), ('enable-skia-graphite'), ...
} // too late — Chromium already initialized the GPU process
start();
The app even logged "Skia Graphite enabled" — because the code path ran — while chrome://gpu reported plain GaneshGL, because the switches were ignored. A trivial await Promise.resolve() before the appendSwitch calls is enough to lose them.
Fix: apply GPU switches at the top level of your main entry, before any await. (Read your settings synchronously with fs.readFileSync if you must — that's exactly what you'd already do for --remote-debugging-port.)
Takeaways
- For Figma's WebGPU shader fills in Electron on Linux/AMD, the path is GaneshGL +
webgpu_on_vk_via_gl_interop, not Skia Graphite. -
--enable-skia-graphiteis a trap on integrated GPUs: it's slower and disables the interop bridge. - The interop switch is
--ozone-platform=x11 --ignore-gpu-blocklist --enable-unsafe-webgpu. - Apply GPU command-line switches before
app.ready, or they're silently dropped. -
getGPUFeatureStatus()lies if you read it too early — read it after first paint.
Reproducible harness, all three chrome://gpu dumps, and the full flag matrix: https://gist.github.com/arximus88/f8d93ae1568a5c49e4206250f323b178.
Project: https://github.com/arximus88/figma-linux-next.
Tested on Electron 42.0.1 / 42.3.0 / 43.0.0-beta.6 (Chrome 148–150), AMD Radeon 780M, Mesa 26.1.2 RADV, GNOME/Wayland.













