https://bugs.kde.org/show_bug.cgi?id=524269
Bug ID: 524269
Summary: GpuManager picks the unaccelerated virtio render node,
exhausting virtio-gpu host resources until the cursor
is drawn at the wrong position — bisected to
23ded4abae
Classification: Plasma
Product: kwin
Version First 6.7.4
Reported In:
Platform: Arch Linux
OS: Linux
Status: REPORTED
Severity: normal
Priority: NOR
Component: platform-drm
Assignee: [email protected]
Reporter: [email protected]
CC: [email protected]
Target Milestone: ---
Created attachment 195161
--> https://bugs.kde.org/attachment.cgi?id=195161&action=edit
Tested fix on top of v6.7.4
In a QEMU/KVM guest using virtio-gpu without 3D acceleration, KWin ≥ 6.7
exhausts
the host's virtio-gpu resource pool within seconds to minutes of normal use.
Once
the pool is exhausted, the drawn cursor stops matching the real pointer
position:
clicks land where the pointer logically is, not where the cursor is painted.
Bisected to **commit 23ded4abae "core: add GpuManager for monitoring render
devices" (Xaver Hugl, 2026-01-24)**. Its direct parent is clean; the commit
itself
produces host resource-allocation failures within ~2 minutes of a fresh boot.
A tested one-commit fix is attached. Setting **`KWIN_RENDER_NODES=` (empty)**
on an otherwise unmodified 6.7.4 also makes the
problem disappear completely, which both confirms the mechanism and provides a
workaround (details below).
## THE MECHANISM
virtio-gpu without virgl exposes a render node (`renderD128`), but it provides
no
acceleration — rendering on it is the same llvmpipe as on the primary node.
Before 23ded4abae, the DRM EGL backend created its GBM/EGL setup on the primary
node fd it already had: rendering and scanout shared one device, and buffers
were
reused directly.
After 23ded4abae, `GpuManager` scans render nodes, finds `renderD128`, and
`DrmGpu::updateRenderDevice()` happily adopts it:
```cpp
if (RenderDevice *renderDev =
GpuManager::self()->compatibleRenderDevice(m_drmDevice.get())) {
setRenderDevice(renderDev); // separate fd for rendering
return;
}
// for software rendering, fall back to the primary node
m_softwareRenderDevice = RenderDevice::open(m_drmDevice->path(), m_fd);
```
Rendering now happens on a separate fd, so every buffer has to be exported from
the
render device and imported into the display device. On virtio-gpu each
guest-side
GEM object is backed by a host-side resource (`RESOURCE_CREATE_2D` +
`ATTACH_BACKING`), and the host's pool for these is finite (QEMU `max_hostmem`,
256 MiB by default). Buffer churn — new windows, new cursor images — creates
resources faster than they are released, and the host starts answering
`VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY`.
Choosing the render node buys nothing here (it is not accelerated) and costs
the
cross-device buffer sharing. The fallback path — primary node, same fd — is
strictly better on this hardware, and forcing it via `KWIN_RENDER_NODES=` fixes
the bug on an unmodified 6.7.4.
## STEPS TO REPRODUCE
1. QEMU/KVM guest, `<video><model type='virtio'/></video>`, **no** `accel3d`
(renderer = llvmpipe). Display type is irrelevant (reproduced with and
without
SPICE).
2. Plasma Wayland session, 1920x1200, scale 1.
3. Open and close LibreOffice (or any application that creates and destroys
windows), and/or move the pointer rapidly across elements with different
cursor
shapes (links vs text in a browser or Telegram Desktop).
4. Watch: `journalctl -b 0 -k | grep -c virtio_gpu_dequeue`
## OBSERVED RESULT
On 6.7.4 the counter starts climbing within seconds and the kernel logs:
```
[drm:virtio_gpu_dequeue_ctrl_func [virtio_gpu]] *ERROR* response 0x1201
(command 0x101)
[drm:virtio_gpu_dequeue_ctrl_func [virtio_gpu]] *ERROR* response 0x1203
(command 0x106)
```
### The visible failure has two stages
**Stage 1 — allocations fail, cursor still correct.** `RESOURCE_CREATE_2D`
fails
with `ERR_OUT_OF_MEMORY`, and `ATTACH_BACKING` fails with
`ERR_INVALID_RESOURCE_ID`
in an exact 1:1 ratio (the guest proceeds against the id that was never created
—
virtio-gpu commands are asynchronous, so no error ever reaches userspace). The
cursor still displays its previously uploaded image correctly.
**Stage 2 — the cursor starts missing.** When `TRANSFER_TO_HOST_2D` (0x105)
starts
failing, the visible symptom appears at exactly that moment (observed twice
with
second-level precision): the drawn cursor no longer matches the real pointer.
Later `RESOURCE_UNREF` (0x102) fails too. Both Wayland-native and Xwayland
clients
are equally affected because only the drawing is wrong; the logical pointer
position stays correct.
This explains why time-to-symptom varies wildly (10 seconds on one build, 15+
minutes on another): what matters is when stage 2 begins, not the raw error
count.
## EXPECTED RESULT
A render device that provides no acceleration should not be preferred over
rendering directly on the primary node. The pre-6.7 behaviour (one device for
rendering and scanout) should be the automatic choice on virtio-2D — exactly
what
the `KWIN_RENDER_NODES=` fallback already does.
## THE BISECT
All builds used the distribution's compiler flags and `setcap
CAP_SYS_NICE=+ep`,
matching packaged builds. The VM was **rebooted before every measurement** —
this
matters, see "Leaked resources" below. Verdict = error counter after
LibreOffice
open/close cycles plus rapid cursor-shape changes.
| commit | date | result |
|---|---|---|
| v6.6.5 (packaged 6.6.5-3) | — | clean: five weeks of daily use, and 0 errors
under the trigger protocol |
| `5bff544fa4` | Mar 6 | clean — 0 errors, >1 hour under load |
| `47de54ec57` (drop wl_drm; direct parent of the culprit) | — | clean — 0
errors in 10 min of the trigger protocol |
| **`23ded4abae` (add GpuManager)** | Jan 24 (merged later) | **54 errors
within ~2 minutes** |
| `bd9b1a5c0b` (prefer render node; child) | — | 21 errors within ~3 minutes |
| later commits (Mar–Jul) | — | all bad, error rate generally increasing |
| v6.7.4 (packaged 6.7.4-3) | — | visible symptom within 10 seconds |
| v6.7.4 + `KWIN_RENDER_NODES=` | — | **0 errors in 10 minutes** of the same
protocol |
The parent/child contrast (0 in 10 min vs eruption in 2 min) is direct, with no
gap between the commits.
### Two later changes amplified the base problem
- **The udmabuf import chain (632314905e, 6e92dc06dd, c7b6faa4f2, c1135c4cb4,
May 5–8)** multiplies resource consumption: client shm buffers become
device-importable dmabufs, so window and cursor client buffers also turn into
virtio host resources. Setting `KWIN_DISABLE_UDMABUF_IMPORT=1` reduced the
error
rate ~4x but did not eliminate it (the shm buffers still carry dmabuf
attributes
and reach the device through the scanout paths). Notably this import is
already
disabled by default on NVIDIA and i915 as problematic.
- **`CAP_SYS_NICE`**: Arch's PKGBUILD has set this capability since January,
but it
only started materializing in the packages between 6.6.5-3 (May 29 — xattr
absent
from the archive) and 6.7.0-1 (Jun 16 — present). Realtime scheduling roughly
triples the error rate (19/min packaged vs 6/min in an identical build
without
the capability). This packaging change is also why the regression *appeared*
to
users to arrive with 6.7.x.
### Leaked resources outlive the compositor
Once the host pool is exhausted, logging out and back in — even into an older,
clean KWin — does not always recover the guest; in our testing only rebooting
the
VM reliably restored a clean state. Anyone bisecting this must reboot between
measurements, or the counter measures the accumulated host state instead of the
build under test.
## TESTED FIX (attached)
The attached patch
(`0001-core-gpumanager-don-t-use-unaccelerated-virtio-rende.patch`,
on top of v6.7.4) queries `VIRTGPU_PARAM_3D_FEATURES` in
`GpuManager::addDevice()`
and skips virtio render nodes that cannot accelerate anything, letting
`DrmGpu::updateRenderDevice()` fall back to the primary node as before 6.7.
Explicitly requested nodes (`KWIN_RENDER_NODES`) bypass the check, and
behaviour on
real hardware or virtio-with-virgl is unchanged.
Verified on this guest: unpatched 6.7.4 shows the visible symptom within 10
seconds; patched 6.7.4 ran 15+ minutes of the trigger protocol with zero
errors.
## WORKAROUND
On any affected version (verified on unmodified packaged 6.7.4):
```
mkdir -p ~/.config/systemd/user/plasma-kwin_wayland.service.d
printf '[Service]\nEnvironment=KWIN_RENDER_NODES=\n' \
> ~/.config/systemd/user/plasma-kwin_wayland.service.d/render-nodes.conf
systemctl --user daemon-reload
```
then relogin. (On Plasma, `/etc/environment` does not reach
`plasma-kwin_wayland.service`; the drop-in or `~/.config/environment.d/` is
required.)
## SUGGESTED FIX
`GpuManager`/`DrmGpu::updateRenderDevice()` should verify that a candidate
render
device actually provides hardware acceleration before preferring it over the
primary-node fallback — effectively restoring the capability check that the old
`drm_egl_backend` logic performed before it was removed in 23ded4abae. On
virtio-2D (and likely other display-only devices) the render node must not win.
## SOFTWARE/OS VERSIONS
- Operating System: Arch Linux (rolling)
- KDE Plasma Version: 6.7.4 (regression range verified 6.6.5 → 6.7.x)
- Qt Version: 6.11.1
- Kernel Version: 7.1.7-hardened1-1-hardened
- Graphics Platform: Wayland
- Mesa: 26.1.6, libdrm 2.4.134
- GPU: virtio-gpu (1af4:1050), no 3D acceleration, renderer = llvmpipe
- Guest under QEMU/KVM (q35); host QEMU untouched throughout, defaults for
`max_hostmem`
## ADDITIONAL NOTES
- Current master appears unaffected *by accident*: the June GpuManager rework
(8533781 "add a RenderDevice backed by udmabuf" and related commits) changed
device selection so that a udmabuf-backed software device is preferred over a
drm-backed software render node, so rendering likely no longer lands on the
virtio render node there. There is however no deliberate virtio/acceleration
check anywhere, and the stable 6.7 branch — which users actually run — is
fully affected, so a 6.7 backport of a fix like the attached one is what's
needed.
- Bug 520650 (doubled cursor in VMs, 6.7.0) lives in the same area but is a
different, already-fixed problem; both regressions came out of the same
render-device refactoring period.
- The `shakecursor` effect independently produces
`KMS: DRM_IOCTL_MODE_CREATE_DUMB failed` (from Mesa's kms_swrast) on this
hardware; unrelated to the main issue, mentioned to save triage time.
--
You are receiving this mail because:
You are watching all bug changes.