Fixes the Wayland/Nvidia startup failure in Tauri v2 apps without disabling hardware acceleration.
Gdk-Message: Error 71 (Protocol error) dispatching to Wayland display.
Your app exits immediately or shows a blank window on startup, with that message on stderr. You are affected if all of these hold:
echo $XDG_SESSION_TYPE # wayland
cat /sys/class/drm/card*/device/vendor # 0x10de somewhere
ls -l /sys/class/drm/card*/device/driver # -> .../drivers/nvidiaBoth the proprietary and the open kernel modules are affected. Nouveau, Intel and AMD are not (as far as has been tested).
GTK decides at the start of every frame whether to draw with GL or into a shared-memory buffer, based on whether the window already has a paint GL context. WebKitGTK only creates one from inside the draw, so the first frame starts as a shared-memory frame and the window's EGL surface appears halfway through it. Nvidia's driver arms explicit sync as soon as that EGL surface exists; GTK then attaches the shared-memory buffer, which carries no acquire point, and the compositor drops the connection.
This plugin creates the GL context up front, so every frame is a GL frame and no shared-memory buffer is ever attached.
| DMA-BUF renderer | Nvidia explicit sync | Scope | |
|---|---|---|---|
WEBKIT_DISABLE_DMABUF_RENDERER=1 |
off | on | process + children |
__NV_DISABLE_EXPLICIT_SYNC=1 |
on | off | process + children |
| this plugin | on | on | one window, in-process |
cargo add tauri-plugin-wayland-nvidia-quirkOn non-affected targets the crate compiles to a no-op with no dependencies.
One line, should be the first alongside your other plugins:
// src-tauri/src/lib.rs
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_wayland_nvidia_quirk::init())
.plugin(tauri_plugin_dialog::init())
.invoke_handler(tauri::generate_handler![/* ... */])
.run(tauri::generate_context!())
.expect("failed to start app");
}init() covers these too. It hooks the process's GtkApplication, which announces every window synchronously as GTK builds it, before the window is realized, and before the event loop draws a frame.
To force the quirk on one window explicitly:
let window = tauri::WebviewWindowBuilder::new(app, "second", Default::default()).build()?;
tauri_plugin_wayland_nvidia_quirk::apply(&window)?;Again, it is a no-op on unaffected systems and safe to call more than once.
.setup(|app| {
println!("quirk: {:?}", tauri_plugin_wayland_nvidia_quirk::status());
Ok(())
})quirk: Applied { gpu: "0x10de", driver: "nvidia", session: Wayland }
quirk: NotAffected { reason: NotNvidia }
quirk: NotAffected { reason: NotWayland }
quirk: Overridden { by: "WEBKIT_DISABLE_DMABUF_RENDERER=1" }
quirk: Failed { error: "no GL context for the window: ..." }
To confirm hardware acceleration survived:
WAYLAND_DEBUG=1 ./your-app 2>&1 | grep -c set_acquire_point # > 0
WAYLAND_DEBUG=1 ./your-app 2>&1 | grep -c "wl_shm_pool.*create_buffer" # 0A correct run sets acquire points and allocates no shared-memory buffers.
A demo app that prints what the plugin decided, and a script that runs it with and without the quirk and reads the protocol trace:
cargo run --manifest-path demos/minimal/Cargo.toml # see it work
./demos/verify.sh # measure itSee demos/. No npm and no tauri-cli needed; not part of the published crate.
| Variable | Effect |
|---|---|
TAURI_WAYLAND_NVIDIA_QUIRK=0 |
Never apply, even if detected |
TAURI_WAYLAND_NVIDIA_QUIRK=1 |
Always apply, skip detection |
TAURI_WAYLAND_NVIDIA_QUIRK_VERBOSE=1 |
Log the decision and every signal to stderr |
Fall back, in this order:
__NV_DISABLE_EXPLICIT_SYNC=1 ./your-app # keeps DMA-BUF, drops explicit sync
WEBKIT_DISABLE_DMABUF_RENDERER=1 ./your-app # drops WebKit's GPU compositingOn a build you cannot recompile, GTK has a built-in equivalent that needs no code:
GDK_GL=always ./your-appThat forces the same early GL context, but for every window in the process, and in every child process that inherits the variable (including WebKitWebProcess), at roughly +5% peak RSS (based on results from kana-trainer app).
Please report failures with your status() output, glxinfo -B, and the driver version from /proc/driver/nvidia/version.
Root-cause analysis, six reproducers and annotated Wayland protocol traces: tauri-v2-wayland-nvidia-issue.
Upstream issues: tauri#10702 · webkit#280210 · gtk#8056 · egl-wayland#179
Apache-2.0