From 9c164ca597d43960aa518a0909488be8029eed85 Mon Sep 17 00:00:00 2001 From: Lam Wei Lun Date: Mon, 12 Oct 2026 13:02:10 +0800 Subject: [PATCH] Linux: use WebKit's shared-memory transport for the NVIDIA DMABUF renderer The Device tab web view is slow on NVIDIA proprietary drivers even with accelerated compositing left on: since the DMABUF renderer became the default in WebKitGTK 2.42, the driver cannot back it, and web views fall back to a slow path. Gating the old WEBKIT_DISABLE_COMPOSITING_MODE fallback on WebKit < 2.42 is the wrong axis, because the failure is version-independent from 2.42 on. Force the shared-memory transport with WEBKIT_DMABUF_RENDERER_FORCE_SHM=1. That keeps compositing and threaded scrolling and skips only the hardware path. Also set WEBKIT_FORCE_DMABUF_RENDERER=1, which clears the isNVIDIA() early return that Debian/Ubuntu/openSUSE patch into rendererBufferTransportMode() and which otherwise returns before the FORCE_SHM check is reached. Both are set before the X11-vs-Wayland split so the workaround also covers XWayland, and only when WebKitGTK is new enough to honour FORCE_SHM (>= 2.44, WebView::SupportsForceSharedMemory()). The AppImage launcher exported the superseded WEBKIT_DISABLE_DMABUF_RENDERER=1, which is read first, leaves the transport set empty and so disables compositing outright; replace it with the same pair. The wxWidgets skill reference is updated to match. --- .../orca-wxwidgets/references/platforms.md | 15 ++++++---- .../references/webview-gl-aui-media.md | 30 +++++++++++++++++-- src/OrcaSlicer.cpp | 8 +++++ .../platform/unix/build_linux_image.sh.in | 3 +- src/slic3r/GUI/Widgets/WebView.cpp | 11 +++++++ src/slic3r/GUI/Widgets/WebView.hpp | 11 +++++-- 6 files changed, 65 insertions(+), 13 deletions(-) diff --git a/.claude/skills/orca-wxwidgets/references/platforms.md b/.claude/skills/orca-wxwidgets/references/platforms.md index c8360cd2e6..6ccdcc134b 100644 --- a/.claude/skills/orca-wxwidgets/references/platforms.md +++ b/.claude/skills/orca-wxwidgets/references/platforms.md @@ -569,13 +569,16 @@ on the **first** call. So: #endif ``` -**Before GTK starts**, only the environment exists. `CLI::run` (`src/OrcaSlicer.cpp`) branches on -`GDK_BACKEND` (an `x11` prefix means the X11 opt-in). On the default path it forces `GDK_BACKEND=x11` -when wx lacks EGL and `WAYLAND_DISPLAY` is set. It sets `WEBKIT_DISABLE_COMPOSITING_MODE=1` -(non-replacing) only when both `DISPLAY` and `WAYLAND_DISPLAY` are set and the linked WebKitGTK is -older than 2.42, and calls `XInitThreads()` +**Before GTK starts**, only the environment exists. `CLI::run` (`src/OrcaSlicer.cpp`) sets the NVIDIA +DMABUF workaround and then branches on `GDK_BACKEND` (an `x11` prefix means the X11 opt-in). On both +paths, when `/proc/driver/nvidia/version` exists and the linked WebKitGTK honours the switch (>= 2.44, +`WebView::SupportsForceSharedMemory()`), it sets `WEBKIT_DMABUF_RENDERER_FORCE_SHM=1` and +`WEBKIT_FORCE_DMABUF_RENDERER=1` (non-replacing): the proprietary driver cannot back WebKit's hardware +DMABUF renderer. On the default path it forces `GDK_BACKEND=x11` when wx lacks EGL and `WAYLAND_DISPLAY` +is set. It sets `WEBKIT_DISABLE_COMPOSITING_MODE=1` (non-replacing) only when both `DISPLAY` and +`WAYLAND_DISPLAY` are set and the linked WebKitGTK is older than 2.42, and calls `XInitThreads()` only when `DISPLAY` is set. With neither variable set, the GUI refuses to start ("Neither DISPLAY nor -WAYLAND_DISPLAY set"). The details and the WebKit rule (c12912e0df) are in +WAYLAND_DISPLAY set"). The details and the WebKit rules (c12912e0df) are in `references/webview-gl-aui-media.md` §WebKitGTK on Linux sessions. **wx's own detectors**, for reference: diff --git a/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md b/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md index 39356d5f2b..e9258c4522 100644 --- a/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md +++ b/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md @@ -568,7 +568,13 @@ vue-resize workaround script and sets a persistent SQLite cookie store on the vi ## WebKitGTK on Linux sessions **Mechanism.** `CLI::run` (`src/OrcaSlicer.cpp`, under `#ifdef __WXGTK__`, before GTK initialises) -branches on `GDK_BACKEND`: +sets the NVIDIA DMABUF workaround and then branches on `GDK_BACKEND`: +- **Both paths**, before the split: when `/proc/driver/nvidia/version` exists and the linked WebKitGTK + honours the switch (>= 2.44, `WebView::SupportsForceSharedMemory()`), it sets + `WEBKIT_DMABUF_RENDERER_FORCE_SHM=1` and `WEBKIT_FORCE_DMABUF_RENDERER=1` non-replacing. The + proprietary driver cannot back WebKit's hardware DMABUF renderer, so the shared-memory transport keeps + compositing and threaded scrolling; `WEBKIT_FORCE_DMABUF_RENDERER` clears the Debian/Ubuntu/openSUSE + `isNVIDIA()` early return, which otherwise returns before the FORCE_SHM check. - **Default path** (`GDK_BACKEND` unset or not starting with `x11`): if wx lacks EGL (`!wxHAS_EGL`) and `WAYLAND_DISPLAY` is set, it forces `GDK_BACKEND=x11`; it sets `WEBKIT_DISABLE_COMPOSITING_MODE=1` non-replacing **only** when the linked WebKitGTK predates 2.42 (`WebView::NeedsCompositingWorkaround()`) @@ -577,13 +583,31 @@ branches on `GDK_BACKEND`: `DISPLAY` is set. - **`GDK_BACKEND=x11…` opt-in path**: sets `DRI_PRIME=1` (and the NVIDIA PRIME variables when `/proc/driver/nvidia/version` exists), calls `XInitThreads()`, and deliberately does **not** disable - compositing (the comment: the WebKit2GTK XWayland bug appears fixed in WebKit2GTK ≥ 2.42, and leaving - compositing on keeps hardware acceleration for Device / Setup Wizard / login pages). + compositing, which keeps hardware acceleration for Device / Setup Wizard / login pages. Runtime backend detection elsewhere uses Orca's `is_running_on_wayland()` / `is_running_on_x11()` (see `references/platforms.md`), not these environment variables. **Pitfall.** +- **Rule:** On NVIDIA reach for `WEBKIT_DMABUF_RENDERER_FORCE_SHM` before + `WEBKIT_DISABLE_COMPOSITING_MODE`. **Why:** the proprietary driver cannot back WebKit's hardware + DMABUF renderer, leaving web views blank or slow; FORCE_SHM keeps compositing and threaded scrolling + and only skips the hardware path, while disabling compositing also turns threaded scrolling off. + `WEBKIT_DISABLE_DMABUF_RENDERER` is not a substitute — it is read first, leaves the transport set + empty (no compositing) and has a reported crash path. On Debian/Ubuntu and openSUSE the `isNVIDIA()` + patch returns before the FORCE_SHM check, so `WEBKIT_FORCE_DMABUF_RENDERER=1` must clear it first. + WebKit reads all of these once per process, before the first WebView. + ```cpp + // Wrong: kills compositing and threaded scrolling (and can crash on modern WebKit) + ::setenv("WEBKIT_DISABLE_DMABUF_RENDERER", "1", false); + // Right: keep compositing, skip only the hardware DMABUF path + if (::access("/proc/driver/nvidia/version", F_OK) == 0 && WebView::SupportsForceSharedMemory()) { + ::setenv("WEBKIT_DMABUF_RENDERER_FORCE_SHM", "1", /*replace*/ false); + ::setenv("WEBKIT_FORCE_DMABUF_RENDERER", "1", /*replace*/ false); + } + ``` + Cite: WebKit 2.52.6 `Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp` + (`rendererBufferTransportMode()`), Debian `disable-nvidia-dmabuf.patch`, WebKit bug 262607. - **Rule:** Set `WEBKIT_DISABLE_COMPOSITING_MODE` only on the default path in Wayland sessions, non-replacing (`setenv(..., false)`, so a value the user already exported wins), before GTK initialises; never unconditionally, and only for the WebKitGTK releases that need it (older than diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 7e6c571134..cb42d60fb9 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -1164,6 +1164,14 @@ int CLI::run(int argc, char **argv) // honours the first backend in the comma-separated list). const bool x11_opt_in = gdk_backend && boost::starts_with(gdk_backend, "x11"); + // NVIDIA's proprietary driver cannot back WebKitGTK's DMABUF renderer. + // Force the shared-memory transport, which keeps compositing and threaded + // scrolling; the second variable clears Debian/Ubuntu/openSUSE's isNVIDIA(). + if (::access("/proc/driver/nvidia/version", F_OK) == 0 && WebView::SupportsForceSharedMemory()) { + ::setenv("WEBKIT_DMABUF_RENDERER_FORCE_SHM", "1", /* replace */ false); + ::setenv("WEBKIT_FORCE_DMABUF_RENDERER", "1", /* replace */ false); + } + if (x11_opt_in) { // ===== X11 / XWayland (opted in via GDK_BACKEND=x11) ===== BOOST_LOG_TRIVIAL(info) << "GDK_BACKEND=x11 detected; applying v2.3.2 X11/XWayland workarounds."; diff --git a/src/dev-utils/platform/unix/build_linux_image.sh.in b/src/dev-utils/platform/unix/build_linux_image.sh.in index 7ccf5a5928..9348686f5e 100755 --- a/src/dev-utils/platform/unix/build_linux_image.sh.in +++ b/src/dev-utils/platform/unix/build_linux_image.sh.in @@ -429,7 +429,8 @@ if [ "\$XDG_SESSION_TYPE" = "wayland" ] && [ "\$ZINK_DISABLE_OVERRIDE" != "1" ]; export __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json export MESA_LOADER_DRIVER_OVERRIDE=zink export GALLIUM_DRIVER=zink - export WEBKIT_DISABLE_DMABUF_RENDERER=1 + export WEBKIT_DMABUF_RENDERER_FORCE_SHM=1 + export WEBKIT_FORCE_DMABUF_RENDERER=1 fi fi fi diff --git a/src/slic3r/GUI/Widgets/WebView.cpp b/src/slic3r/GUI/Widgets/WebView.cpp index 191b849a42..5fec4ced36 100644 --- a/src/slic3r/GUI/Widgets/WebView.cpp +++ b/src/slic3r/GUI/Widgets/WebView.cpp @@ -417,6 +417,17 @@ bool WebView::NeedsCompositingWorkaround() #endif } +bool WebView::SupportsForceSharedMemory() +{ +#ifdef __linux__ + const guint major = webkit_get_major_version(); + const guint minor = webkit_get_minor_version(); + return major > 2 || (major == 2 && minor >= 44); +#else + return false; +#endif +} + #if wxUSE_WEBVIEW_EDGE bool WebView::CheckWebViewRuntime() { diff --git a/src/slic3r/GUI/Widgets/WebView.hpp b/src/slic3r/GUI/Widgets/WebView.hpp index ac4aaab0b3..e48d0ccf0a 100644 --- a/src/slic3r/GUI/Widgets/WebView.hpp +++ b/src/slic3r/GUI/Widgets/WebView.hpp @@ -30,11 +30,16 @@ public: // ignoring every navigation. A panel that gets true here recreates its view on first Show(). static bool NeedsRecreateOnShow(); - // True when the linked WebKitGTK predates the fix for the XWayland accelerated - // compositing bug (< 2.42), so accelerated compositing must be forced off. False - // on every other platform. Safe to call before GTK initialises. + // True when the linked WebKitGTK predates 2.42, where accelerated compositing + // could fail silently on XWayland sessions, so it is forced off as a fallback. + // False on every other platform. Safe to call before GTK initialises. static bool NeedsCompositingWorkaround(); + // True when the linked WebKitGTK is new enough (>= 2.44) to honour + // WEBKIT_DMABUF_RENDERER_FORCE_SHM, the shared-memory transport switch. + // False on every other platform. Safe to call before GTK initialises. + static bool SupportsForceSharedMemory(); + static void RecreateAll(); };