diff --git a/.claude/skills/orca-wxwidgets/references/platforms.md b/.claude/skills/orca-wxwidgets/references/platforms.md index f391aecf27..0ec78aaa43 100644 --- a/.claude/skills/orca-wxwidgets/references/platforms.md +++ b/.claude/skills/orca-wxwidgets/references/platforms.md @@ -569,12 +569,18 @@ 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 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, and sets `WEBKIT_DISABLE_COMPOSITING_MODE=1` (non-replacing) inside that branch when the linked +WebKitGTK is older than 2.42: a forced X11 backend in a Wayland session is the only default-path case +that runs through XWayland, which `DISPLAY` and `WAYLAND_DISPLAY` alone do not tell you (a native +Wayland app inherits both). It 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 b8856b21ca..e7ff4fadde 100644 --- a/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md +++ b/.claude/skills/orca-wxwidgets/references/webview-gl-aui-media.md @@ -61,7 +61,8 @@ available; GTK2/WebKit1 is an opt-out configuration the GUI does not support. 11. A web host that re-themes in place handles `EVT_WEBVIEW_RECREATED` without `Skip()`; one that needs a reload lets it through. §[Orca wrapper](#orca-webview-wrapper-widgetswebview) 12. Keep `WebViewWebKit`'s destructor removing the `"wx"` handler. §[Orca wrapper](#orca-webview-wrapper-widgetswebview) -13. Do not widen `WEBKIT_DISABLE_COMPOSITING_MODE` beyond Orca's default-path XWayland case, and never +13. Do not widen `WEBKIT_DISABLE_COMPOSITING_MODE` beyond the no-EGL default path where Orca forces + `GDK_BACKEND=x11`, for WebKitGTK older than 2.42, and never make a page's progress depend only on a C++→JS callback. §[WebKitGTK on Linux](#webkitgtk-on-linux-sessions) 14. GL attribute lists: legacy `int[]` lists end with `0` and spell out `WX_GL_RGBA` and `WX_GL_DOUBLEBUFFER`; `wxGLAttributes`/`wxGLContextAttrs` end with `EndList()`; MSAA is requested @@ -567,33 +568,69 @@ 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 + accelerated compositing instead of dropping it; `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 both `DISPLAY` and `WAYLAND_DISPLAY` are non-empty (a Wayland session with - XWayland available — the session, not the backend GTK will pick); `XInitThreads()` runs only when - `DISPLAY` is set. + `WAYLAND_DISPLAY` is set, it forces `GDK_BACKEND=x11`, and in that same branch it sets + `WEBKIT_DISABLE_COMPOSITING_MODE=1` non-replacing when the linked WebKitGTK predates 2.42 + (`WebView::NeedsCompositingWorkaround()`). That forced X11 backend in a Wayland session is the only + default-path case that really runs through XWayland; `DISPLAY` and `WAYLAND_DISPLAY` alone do not + identify it, because a native Wayland app inherits both. `XInitThreads()` runs only when `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:** 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. Keep JS-side fallbacks so a page never +- **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 accelerated compositing and only + skips the hardware path, while disabling compositing drops it. Threaded scrolling is a separate, + release-dependent default (off in 2.44/2.45, on from 2.46). `WEBKIT_DISABLE_DMABUF_RENDERER` is not a + substitute — it is read first, leaves the transport set empty (no compositing from 2.44 on, where the + X11/Wayland fallback renderers were removed) 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; that variable exists only in those patches. WebKit reads all of these once per + process, before the first WebView. + The test is `/proc/driver/nvidia/version`, so a hybrid laptop that renders on its iGPU also takes the + shared-memory path, which is a per-frame GPU readback rather than zero-copy; exporting + `WEBKIT_DMABUF_RENDERER_FORCE_SHM=0` in the environment restores the hardware path. + ```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 the branch where wx + lacks EGL and Orca forces `GDK_BACKEND=x11`, 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 + 2.42, `WebView::NeedsCompositingWorkaround()`). Keep JS-side fallbacks so a page never waits forever for a C++→JS call. - **Why:** WebKit2GTK accelerated compositing could fail silently under XWayland, leaving web views - blank (Setup Wizard stuck on "Loading..."); disabling it everywhere needlessly drops hardware - acceleration; without the JS timeout the user is stuck when the signal is lost. + **Why:** WebKit2GTK accelerated compositing could fail silently under XWayland before 2.42, leaving + web views blank (Setup Wizard stuck on "Loading..."); the variable also turns off threaded scrolling, + so applying it on a newer WebKit needlessly drops both GPU compositing and async scrolling (the + Device tab loses its smoothness); without the JS timeout the user is stuck when the signal is lost. ```cpp // Wrong: unconditional, kills HW acceleration everywhere ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", false); - // Right (default path only): non-replacing, before GTK init, Wayland session with XWayland - if (display && *display && wayland && *wayland) + // Right (default path only): non-replacing, before GTK init, WebKitGTK < 2.42, + // and only in the branch that forces GDK_BACKEND=x11 (wx without EGL), the + // case that runs through XWayland + if (WebView::NeedsCompositingWorkaround() && wayland && *wayland) ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /*replace*/ false); ``` Cite: c12912e0df (`src/OrcaSlicer.cpp`; `resources/web/guide/0/load.js` `OnInit` diff --git a/scripts/flatpak/entrypoint b/scripts/flatpak/entrypoint index f8e108e85f..7137c3798d 100644 --- a/scripts/flatpak/entrypoint +++ b/scripts/flatpak/entrypoint @@ -1,7 +1,7 @@ #!/usr/bin/env sh -# Work-around https://gitlab.gnome.org/GNOME/gnome-build-meta/-/issues/754 -grep -q org.freedesktop.Platform.GL.nvidia /.flatpak-info && export WEBKIT_DISABLE_DMABUF_RENDERER=1 +# WebKit's NVIDIA DMABUF workaround (gnome-build-meta#754) is applied by the +# binary itself, gated on the runtime WebKitGTK version (src/OrcaSlicer.cpp). # Work-around https://github.com/bambulab/BambuStudio/issues/3440 # Use LC_NUMERIC instead of LC_ALL to prevent decimal separator issues diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index ef0e4bbe3a..468cfb9a30 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -163,6 +163,7 @@ using json = nlohmann::json; #include #endif #include +#include "slic3r/GUI/Widgets/WebView.hpp" #endif #ifdef SLIC3R_GUI @@ -1156,8 +1157,10 @@ int CLI::run(int argc, char **argv) // opt-in path. The ~2020-era WebKit2GTK XWayland compositor bug it // worked around appears fixed in WebKit2GTK >= 2.42; leaving it // unset preserves WebKit hardware acceleration on Device / Setup - // Wizard / login / store. The default path still applies it on - // XWayland sessions as a conservative fallback for older WebKit. + // Wizard / login / store. The default path applies it only where it + // forces GDK_BACKEND=x11 below (a build without EGL, so the app really + // runs through XWayland), and only when the linked WebKitGTK predates + // the fix (< 2.42), as a conservative fallback for older WebKit. // ------------------------------------------------------------------ { const char* gdk_backend = ::getenv("GDK_BACKEND"); @@ -1165,6 +1168,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."; @@ -1204,23 +1215,18 @@ int CLI::run(int argc, char **argv) if (wayland_env && *wayland_env) { BOOST_LOG_TRIVIAL(warning) << "Wayland detected but wxWidgets has no EGL support (wxHAS_EGL is OFF). Forcing X11 backend."; ::setenv("GDK_BACKEND", "x11", true); + + // GTK will use X11 in a Wayland session here, which is the + // one default-path case that really runs through XWayland. + // WebKit2GTK accelerated compositing could fail silently + // there on releases before 2.42, so force it off. Disabling + // it also turns off threaded scrolling, hence the gate. + if (WebView::NeedsCompositingWorkaround()) + ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false); } } #endif - // WebKit2GTK compositing can fail under XWayland on older - // WebKit releases. Disable it only when both DISPLAY and - // WAYLAND_DISPLAY are set (i.e. an XWayland session is in - // use). On pure X11 or native Wayland, compositing is left - // enabled so WebKit retains HW acceleration. - { - const char* display_env_wk = ::getenv("DISPLAY"); - const char* wayland_env_wk = ::getenv("WAYLAND_DISPLAY"); - if (display_env_wk && *display_env_wk && wayland_env_wk && *wayland_env_wk) { - ::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false); - } - } - // XInitThreads is needed before GStreamer may use Xlib. On // native Wayland without DISPLAY, GStreamer uses waylandsink // (no Xlib involved), so the call is skipped. 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..a7f99ba775 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 + # WebKit's NVIDIA DMABUF workaround is applied by the binary itself, + # gated on the runtime WebKitGTK version (src/OrcaSlicer.cpp). fi fi fi diff --git a/src/slic3r/GUI/Widgets/WebView.cpp b/src/slic3r/GUI/Widgets/WebView.cpp index 7af3ba4f1d..dde4df385a 100644 --- a/src/slic3r/GUI/Widgets/WebView.cpp +++ b/src/slic3r/GUI/Widgets/WebView.cpp @@ -74,6 +74,10 @@ webkit_web_view_run_javascript_finish (WebKitWebView GError **error); WEBKIT_API void webkit_javascript_result_unref (WebKitJavascriptResult *js_result); +WEBKIT_API guint +webkit_get_major_version (void); +WEBKIT_API guint +webkit_get_minor_version (void); } #endif @@ -427,6 +431,29 @@ bool WebView::NeedsRecreateOnShow() return false; #endif } + +bool WebView::NeedsCompositingWorkaround() +{ +#ifdef __linux__ + const guint major = webkit_get_major_version(); + const guint minor = webkit_get_minor_version(); + return major < 2 || (major == 2 && minor < 42); +#else + return false; +#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 bef8a4a101..0692400719 100644 --- a/src/slic3r/GUI/Widgets/WebView.hpp +++ b/src/slic3r/GUI/Widgets/WebView.hpp @@ -34,6 +34,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 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(); };