Fixing Chromium virtual backgrounds on NVIDIA + Wayland
Meet's background blur turns your video into a solid white rectangle on NVIDIA + Wayland Chromium. The cause is a Chromium ↔ NVIDIA EGL interop bug in the canvas captureStream path. Two flags work around it; pick based on monitor setup.
Switched on background blur in a Meet call and turned into a flat white rectangle. Camera works fine without the effect. The moment any background filter (blur or virtual background) is applied, everyone on the call (me in the self-preview included) sees a solid white frame where my video should be. Reproduces in any Chromium-based browser (Chromium, Vivaldi). Firefox is fine. Setup that hits this: NVIDIA proprietary driver (tested on 595.71.05, open kernel module branch, RTX 4090), KDE Plasma 6 on Wayland (Bazzite), Flatpak Chromium 147.
# Why it breaks
Meet's virtual background pipeline runs per frame:
camera frame
→ MediaPipe TFLite WebGL segmentation
→ WebGL composite shader (frame + background, masked)
→ canvas.captureStream() → MediaStream
→ WebRTC encoder
The captureStream() hop has to share the WebGL output texture cross-process to the GPU process where the encoder runs. Chromium does this through its SharedImage abstraction, which on Linux maps to EGLImage / dmabuf. On NVIDIA's Wayland EGL implementation, the shared image arrives at the encoder side either uninitialised or wrongly synchronised, so reads come back as all-1s. Solid white frames.
The shader runs and the composite is correct. The readback path is the broken thing.
Firefox doesn't hit this because it doesn't use ANGLE or Chromium's SharedImage. Its captureStream goes through a different path (often a CPU readback) that never exercises the broken NVIDIA EGL interop.
# Fix
Two flags work. Pick one based on monitor setup.
# Option 1: --ozone-platform=x11 (preferred on a desktop with same-scale monitors)
Runs Chromium under XWayland. GPU compositing stays on, WebGL/canvas/video decode stay full-speed, PipeWire screen sharing still works (it's independent of Ozone). Cost:
- XWayland is integer-scale only. No fractional HiDPI, no proper per-monitor scaling.
- Drag-and-drop and clipboard with native Wayland apps can be slightly flaky.
Fine on a desktop with one or two monitors at the same scale. Annoying if you mix a 4K-at-200% panel with a 1080p-at-100% one.
# Option 2: --disable-gpu-compositing (preferred on laptops or mixed-scale monitors)
Wayland-native integration kept. Compositor runs on CPU. WebGL and canvas individual draws still hit the GPU; only the final composite is software. Cost:
- Continuous extra CPU usage.
- Less smooth scrolling on heavy pages.
- Worse battery on laptops.
Genuinely unnoticeable on a 4090 desktop. Can matter on a laptop.
# How to apply (Flatpak Chromium)
Don't edit the system .desktop file. Flatpak rewrites it on every update. Copy it to ~/.local/share/applications/ instead and edit the local copy. KDE picks up the local override automatically:
cp /var/lib/flatpak/exports/share/applications/org.chromium.Chromium.desktop \
~/.local/share/applications/
Add the chosen flag to all three Exec= lines (main, "New Window" action, "New Incognito Window" action). For Option 1 the main line becomes:
Exec=/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=/app/bin/chromium --file-forwarding org.chromium.Chromium --ozone-platform=x11 @@u %U @@
Quit Chromium fully and relaunch. Verify in chrome://gpu: "Ozone platform" should now read x11, or under Option 2 "Compositing" should read software-only.
For Vivaldi the equivalent lives in ~/.config/vivaldi-stable.conf. Same flags, see Persistent CLI flags for Vivaldi on Linux for the conf-file syntax.
# Things I tried that didn't work
For future-me, so I don't bisect them again. None of these fix it:
--disable-features=WebRtcVideoCaptureGpuMemoryBuffer. Disables zero-copy GPU buffers for camera capture. The camera path is fine, the bug doesn't live here.--disable-features=WebRtcVideoCaptureGpuMemoryBuffer,VaapiVideoDecoder. Adds VA-API decode disable on top. Same outcome.--use-angle=gl. Forces ANGLE off Vulkan onto plain GL. The ANGLE backend isn't the broken thing.--disable-features=WebRTCPipeWireCamera. Falls back to V4L2 capture. Doesn't matter; camera path is fine.--disable-features=Vulkan. Kills Vulkan everywhere. The shared-image bug doesn't go through Vulkan in this configuration.--disable-accelerated-2d-canvas. Forces 2D canvas to CPU. MediaPipe outputs from a WebGL canvas, so this is the wrong canvas.
Only the two flags above cross the broken path entirely (Ozone on X11 sidesteps the NVIDIA Wayland EGL path; --disable-gpu-compositing forces a CPU readback that doesn't need shared images at all).
# The real fix lives upstream
This is a Chromium ↔ NVIDIA Wayland EGL interop bug. Almost certainly already tracked in issues.chromium.org. Worth searching with terms like chromium wayland nvidia canvas captureStream white or MediaPipe NVIDIA Wayland virtual background before filing anything new.
Could also end up being a Flathub packaging fix. The Chromium flatpak already pre-applies --enable-features=WebRTCPipeWireCapturer for exactly this kind of platform-specific compatibility patch, so a future build could ship one of these flags by default for NVIDIA users.
# Related
- Persistent CLI flags for Vivaldi on Linux. Same flags, applied via Vivaldi's conf-file mechanism.
- Bazzite: an immutable gaming-first Fedora variant. Why the browser is a Flatpak in the first place.
- Making 1Password browser extensions talk to the Flatpak desktop app. Another Flatpak browser quirk worth knowing about.