Skip to content

[Bug] Invisible/transparent window on AMD RDNA4: WebKitGTK Skia GPU path fails on non-conformant radv; WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 fixes it #2643

Open

Description

@bealmot

Describe the bug

On AMD RDNA4 GPUs (Mesa radv still marks gfx1200 non-conformant), the Buzz Desktop window is invisible/transparent: the window opens, but the webview never paints (or paints one frame and then permanently stops repainting after any move/minimize). Because the Tauri window is configured with "transparent": true (desktop/src-tauri/tauri.conf.json), the failure presents as a ghost window — desktop wallpaper visible through a Buzz-shaped frame, titlebar rendered normally.

The root cause is not the dmabuf renderer issue from #2338 (that workaround does not help here). WebKitGTK 2.52 renders via Skia, and on this GPU Skia's GPU path goes through Vulkan/radv, which self-reports:

WARNING: radv is not a conformant Vulkan implementation, testing use only.

Forcing Skia to CPU rasterization fully fixes rendering:

WEBKIT_SKIA_ENABLE_CPU_RENDERING=1

To Reproduce

  1. Machine with an AMD RDNA4 GPU (tested: RX 9060 XT / gfx1200), Mesa 26.1.2, KDE Plasma 6.6.5 (Wayland session)
  2. Launch Buzz Desktop (either the 0.4.23 AppImage after the [Bug] fix-appimage.sh doesn't remove bundled libsystemd.so.0 — AppImage crashes on distros with newer systemd (Arch, Fedora 41+, etc.) #2335 libsystemd fix, or a from-source just dev build using system webkit2gtk-4.1 2.52.4 — both reproduce)
  3. Window opens; content area is transparent (or paints the page background once, then goes permanently transparent after moving/minimizing the window)
  4. Relaunch with WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 → full UI renders correctly and survives move/minimize

Expected behavior

The window should render its content, or fall back to a rendering path that works instead of an invisible window.

Supporting Material

Isolation matrix (all on the same machine/session):

Configuration Result
Default (XWayland, GDK_BACKEND=x11 from AppRun hook) transparent
WEBKIT_DISABLE_DMABUF_RENDERER=1 (the #2338 workaround) WebKitWebProcess stays alive, still transparent
GDK_BACKEND=wayland (native Wayland; no eglMakeCurrent failure on AMD, unlike tauri#8541 on Intel) transparent
LIBGL_ALWAYS_SOFTWARE=1 transparent (expected in hindsight — Skia uses Vulkan here, not GL)
WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 renders correctly

Notes:

  • Reproduces identically with the bundled WebKitGTK (0.4.23 AppImage) and the system WebKitGTK 2.52.4 (from-source just dev), on both X11 and native Wayland — so it is not an AppImage packaging problem; it is the Skia GPU path on this GPU generation.
  • WebKitWebProcess and WebKitNetworkProcess run normally throughout; frontend JS executes (Vite client console messages come through in dev). Only painting is broken.
  • Distinct failure mode from [Bug] WebKitGTK dmabuf renderer core dump #2338 (Intel: core dump, fixed by disabling dmabuf; RDNA4: silent no-paint, dmabuf var irrelevant).

Environment

  • OS: CachyOS (Arch-based), KDE Plasma 6.6.5, Wayland session (rootless XWayland)
  • GPU: AMD Radeon RX 9060 XT (RDNA4 / gfx1200), Mesa 26.1.2-arch2.1 (radv)
  • WebKitGTK: bundled (0.4.23 AppImage) and system 2.52.4-1 — both affected
  • Buzz: 0.4.23 AppImage and from-source at current main — both affected

Additional context

Suggested mitigations, in increasing order of effort:

  1. Document WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 as a known workaround for AMD GPUs that radv flags non-conformant (currently RDNA4).
  2. Set it conditionally in the AppRun hook when radv reports a non-conformant device (or expose a --safe-rendering launch flag).
  3. Reconsider unconditional "transparent": true on the main window — when the webview fails to paint for any reason, transparency turns a diagnosable "blank window" into a confusing invisible app. An opaque fallback background would make every rendering bug in this class far more user-debuggable.

Happy to test patches on this hardware.

Related: #2338 (different root cause, same symptom neighborhood), #2335 (libsystemd fix needed first to even launch the AppImage on Arch).

Activity

  1. chessing234 commented on Jul 24, 2026

    @chessing234
    Contributor

    Fix in #2689: default WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 for Linux/AppImage.

  2. bealmot commented on Jul 27, 2026

    @bealmot
    Author

    Confirming resolution on the original hardware (RX 9060 XT / gfx1200, radv, webkit2gtk-4.1 2.52.4, KDE Plasma on Wayland, Arch/CachyOS), with details that may be useful for #2689's scope:

    WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 fixes the Skia paint failure as filed, but on this setup three additional vars were needed for a fully working window:

    • GDK_BACKEND=x11 — under Plasma Wayland the window blanks/crashes on the native Wayland backend (matches the workaround already in the AppImage GTK hook).
    • WEBKIT_DISABLE_DMABUF_RENDERER=1 — content renders once, then goes transparent after first paint (same family as [Bug] WebKitGTK dmabuf renderer core dump #2338).
    • WEBKIT_DISABLE_COMPOSITING_MODE=1 — with the Tauri window's transparent: true, accelerated compositing paints the surface transparent instead of opaque even with Skia CPU rendering on; disabling compositing was the piece that finally made the window fully opaque.

    With all four set, the current build (0.4.26, native Linux binary) renders and runs correctly. So if #2689 only defaults the Skia var, RDNA4+Wayland users will likely still hit the compositing/dmabuf transparency — might be worth defaulting the set together on Linux, or documenting them.

    Happy to test a build with #2689 applied.

  3. wpfleger96 commented on Jul 27, 2026

    @wpfleger96
    Member

    🤖 @bealmot — thanks for the four-var confirmation on the original hardware, that data is directly shaping the fix.

    One isolation test would settle a design question, if you're willing: at the WebKitGTK source level (2.52.4/2.52.5), WEBKIT_DISABLE_DMABUF_RENDERER=1 and WEBKIT_DISABLE_COMPOSITING_MODE=1 converge on the identical preference state (both drive canUseHardwareAcceleration=false, and WebPreferencesGtk.cpp then sets the same {acceleratedCompositing=false, forceCompositing=false} pair) — which suggests one of them may be redundant in your recipe. But source semantics and driver behavior don't always agree, so we'd rather test than assume.

    Could you try launching with only these three:

    GDK_BACKEND=x11 WEBKIT_DISABLE_DMABUF_RENDERER=1 WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 buzz-desktop

    i.e. your working recipe minus WEBKIT_DISABLE_COMPOSITING_MODE=1, and report whether the window still renders correctly?

    • If yes → we ship the narrower three-var set as the terminal fallback profile.
    • If no → we keep the fourth var and document it as an empirically necessary duplicate that source semantics alone don't explain.

    Either answer is useful. Thanks again for offering to test builds — we'll likely take you up on that when the automatic-recovery work reaches a testable state.

  4. bealmot commented on Jul 27, 2026

    @bealmot
    Author

    Tested as requested — yes, the three-var set renders correctly; WEBKIT_DISABLE_COMPOSITING_MODE=1 is empirically redundant here.

    Method, same hardware as before (RX 9060 XT / gfx1200, radv, webkit2gtk-4.1 2.52.4, Plasma Wayland → app on XWayland, native 0.4.26 Linux binary):

    1. Fresh launch with exactly GDK_BACKEND=x11 WEBKIT_DISABLE_DMABUF_RENDERER=1 WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 (verified via /proc/<pid>/environ that the compositing var was absent).
    2. Initial paint: fully opaque, complete workspace (channels, message history, composer) — not just the splash.
    3. Because our original compositing-var symptom was late-onset transparency (content went transparent after first paint), I soaked it ~7 minutes with real content, plus minimize/restore cycles: still fully rendered throughout.

    So on this setup your source-level read holds: with the dmabuf renderer disabled, the compositing path never re-enables whatever the transparent: true surface needed the fourth var for. Narrower three-var set works as the terminal fallback profile.

    One honest caveat for scope: the run where the fourth var appeared necessary was on the older AppImage build, which had a confound (its bundled GStreamer was incomplete, wedging the WebProcess) — so that observation shouldn't count as evidence against the three-var set. On the current native binary, three vars are sufficient.

    Standing by for the automatic-recovery build when it's testable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions