mirror of
https://github.com/cline/cline.git
synced 2026-10-25 10:26:36 +08:00
fix(desktop): disable WebKitGTK DMA-BUF renderer on NVIDIA Linux (#14687)
On Linux with the proprietary NVIDIA driver the desktop app window opens but stays blank. The sidecar/hub is healthy; only rendering fails, with stderr showing: KMS: DRM_IOCTL_MODE_CREATE_DUMB failed: Permission denied Failed to create GBM buffer of size 1500x980: Permission denied This is the known WebKitGTK DMA-BUF/NVIDIA incompatibility documented by Tauri (https://v2.tauri.app/develop/debug/linux-graphics/), whose fix is to set WEBKIT_DISABLE_DMABUF_RENDERER before the webview is created. When /sys/module/nvidia is loaded and the variable is not already set, set it to "1" as the first statement in main(), before tauri::Builder and any threads. Existing values (including "0" and empty) are left alone so users on hybrid-GPU systems can opt back into the DMA-BUF path with WEBKIT_DISABLE_DMABUF_RENDERER=0. Done in the executable rather than the .desktop launcher so terminal launches and every package format benefit. Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
This commit is contained in:
co-authored by
Saoud Rizwan
parent
f58bc118bd
commit
816513fded
@@ -365,6 +365,17 @@ credentials, request headers, recorded audio, or transcript contents.
|
||||
- Tauri restarts the desktop backend if the sidecar process exits and kills it on app teardown.
|
||||
- Chat sends now preflight provider credentials. If a provider that requires API-key auth is selected without a key, the UI blocks the turn with a clear error message instead of starting a hanging session.
|
||||
- If a turn completes with `finishReason=error` before any assistant content is produced, the UI now adds an explicit error chat message so failed turns are visible in the transcript.
|
||||
- Linux with the proprietary NVIDIA driver: WebKitGTK's DMA-BUF renderer
|
||||
fails there (`KMS: DRM_IOCTL_MODE_CREATE_DUMB failed: Permission denied`,
|
||||
`Failed to create GBM buffer ...: Permission denied`) and the window stays
|
||||
blank, so when `/sys/module/nvidia` is loaded the app sets
|
||||
`WEBKIT_DISABLE_DMABUF_RENDERER=1` before creating the webview (see
|
||||
[Tauri's Linux graphics guide](https://v2.tauri.app/develop/debug/linux-graphics/)).
|
||||
This also matches hybrid-GPU systems where another GPU renders, which then
|
||||
lose the faster DMA-BUF path (not hardware acceleration as a whole). To opt
|
||||
out, fully Quit from the tray (closing the window only hides it) and launch
|
||||
with `WEBKIT_DISABLE_DMABUF_RENDERER=0 cline-app`; any value you set is
|
||||
left untouched.
|
||||
- If package changes are not reflected, rebuild SDK packages (`bun run build:sdk`).
|
||||
The next desktop or CLI Hub connection will reuse a compatible running Hub or
|
||||
replace an incompatible one through the shared discovery path.
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
//! WebKitGTK's DMA-BUF renderer does not work on the proprietary NVIDIA
|
||||
//! driver: the window opens but stays blank while stderr reports
|
||||
//! `KMS: DRM_IOCTL_MODE_CREATE_DUMB failed: Permission denied` and
|
||||
//! `Failed to create GBM buffer of size WxH: Permission denied`. The sidecar
|
||||
//! is healthy; only rendering fails. Tauri's guidance is to set
|
||||
//! `WEBKIT_DISABLE_DMABUF_RENDERER` before the webview is created:
|
||||
//! https://v2.tauri.app/develop/debug/linux-graphics/
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
const DMABUF_RENDERER_VAR: &str = "WEBKIT_DISABLE_DMABUF_RENDERER";
|
||||
const NVIDIA_MODULE_PATH: &str = "/sys/module/nvidia";
|
||||
|
||||
/// Must run before `tauri::Builder` and before any thread is spawned: WebKit
|
||||
/// reads the variable during initialization, and mutating the environment is
|
||||
/// only sound while the process is still single-threaded.
|
||||
pub fn configure_environment() {
|
||||
if should_disable_dmabuf_renderer(
|
||||
Path::new(NVIDIA_MODULE_PATH).is_dir(),
|
||||
std::env::var_os(DMABUF_RENDERER_VAR).as_deref(),
|
||||
) {
|
||||
std::env::set_var(DMABUF_RENDERER_VAR, "1");
|
||||
}
|
||||
}
|
||||
|
||||
/// Gated on the loaded NVIDIA kernel module rather than arch or session type
|
||||
/// (the failure reproduces on ARM64/X11 too). Any value the user already set
|
||||
/// is left alone, including "0" and the empty string, so the documented
|
||||
/// opt-out (`WEBKIT_DISABLE_DMABUF_RENDERER=0`) keeps working on hybrid-GPU
|
||||
/// systems where another GPU does the rendering.
|
||||
fn should_disable_dmabuf_renderer(nvidia_module_loaded: bool, current: Option<&OsStr>) -> bool {
|
||||
nvidia_module_loaded && current.is_none()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
#[test]
|
||||
fn disables_the_renderer_when_nvidia_is_loaded_and_the_var_is_unset() {
|
||||
assert!(should_disable_dmabuf_renderer(true, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaves_the_renderer_alone_without_the_nvidia_module() {
|
||||
assert!(!should_disable_dmabuf_renderer(false, None));
|
||||
assert!(!should_disable_dmabuf_renderer(
|
||||
false,
|
||||
Some(OsStr::new("1"))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_an_explicit_opt_out() {
|
||||
assert!(!should_disable_dmabuf_renderer(true, Some(OsStr::new("0"))));
|
||||
assert!(!should_disable_dmabuf_renderer(true, Some(OsStr::new(""))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_a_non_utf8_value() {
|
||||
assert!(!should_disable_dmabuf_renderer(
|
||||
true,
|
||||
Some(OsStr::from_bytes(b"\xff"))
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux_webview;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos_notification;
|
||||
|
||||
@@ -1465,6 +1467,11 @@ fn set_tray_status(
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Must stay first: WebKitGTK reads the environment while initializing,
|
||||
// and the variable has to be in place before any thread exists.
|
||||
#[cfg(target_os = "linux")]
|
||||
linux_webview::configure_environment();
|
||||
|
||||
let desktop_backend = Arc::new(DesktopBackendState::default());
|
||||
let launch_cwd = std::env::current_dir()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
|
||||
Reference in New Issue
Block a user