https://bugs.kde.org/show_bug.cgi?id=527879

            Bug ID: 527879
           Summary: linux-drm-syncobj-v1 is never advertised on FreeBSD:
                    the kernel-version check treats every non-Linux system
                    as kernel 0.0.0
    Classification: Plasma
           Product: kwin
      Version First 6.7.5
       Reported In:
          Platform: Other
                OS: Linux
            Status: REPORTED
          Severity: normal
          Priority: NOR
         Component: wayland-generic
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

## Summary

`WaylandServer::setRenderBackend()` advertises
`wp_linux_drm_syncobj_manager_v1`
only if `linuxKernelVersion() >= 6.6`. `linuxKernelVersion()`
(`src/utils/kernel.h`) returns `Version(0, 0, 0)` whenever `uname().sysname` is
not `"Linux"`. On FreeBSD the check therefore always fails and explicit sync is
never offered to clients, even though the DRM driver supports timeline syncobjs
and `DRM_IOCTL_SYNCOBJ_EVENTFD`. This is the ioctl that the version check is
meant to guard.

On NVIDIA this has a real cost. Without explicit sync, and with the compositor
on an NVIDIA device, NVIDIA's `egl-wayland2` client platform cannot use
implicit sync either. It falls back to a `glFinish()` on every
`eglSwapBuffers`, and the driver's `glFinish()` busy-waits. A Qt OpenGL client
animating at 60 fps uses about 14–20% of one CPU core on Wayland, against about
1.5% on X11.

## Environment

- FreeBSD 15.1-RELEASE amd64
- KWin / Plasma 6.7.5, KDE Frameworks 6.31.0, Qt 6.11.2
- NVIDIA RTX A400, driver 615.78.08 (also seen with 595.112.07),
  nvidia-drm-612-kmod, drm-612-kmod 6.12.85
- egl-wayland2 1.0.2, libdrm, libwayland 1.26.0

## The code

`src/wayland_server.cpp` (v6.7.5):

```cpp
void WaylandServer::setRenderBackend(RenderBackend *backend)
{
    if (backend->drmDevice()->supportsSyncObjTimelines()) {
        // ensure the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl is supported
        const auto linuxVersion = linuxKernelVersion();
        if (linuxVersion < Version(6, 6)) {
            return;
        }
        ...
```

`src/utils/kernel.h`:

```cpp
inline static Version linuxKernelVersion()
{
    struct utsname name;
    uname(&name);

    if (qstrcmp(name.sysname, "Linux") == 0) {
        return Version::parseString(name.release);
    }
    return Version(0, 0, 0);
}
```

## Evidence

1. **The global is missing.** With `WAYLAND_DEBUG=1`, a client's registry
   contains `wp_presentation`, `zwp_linux_dmabuf_v1` (v5) and the others, but
no
   `wp_linux_drm_syncobj_manager_v1`.

2. **The driver supports what KWin needs.** A small libdrm test on
   `/dev/dri/card0` (`nvidia-drm`) shows:

   ```
   DRM_CAP_SYNCOBJ           ret=0 val=1
   DRM_CAP_SYNCOBJ_TIMELINE  ret=0 val=1
   drmSyncobjCreate          ret=0
   drmSyncobjEventfd         ret=0     (real syncobj, point 1, eventfd from
eventfd(2))
   drmSyncobjQuery           ret=0
   drmSyncobjEventfd on handle 0 -> ENOENT   (ioctl known, handle invalid)
   ```

   `supportsSyncObjTimelines()` is therefore true. Only the version check stops
   the protocol from being advertised.

3. **What the client does instead.** A debug build of egl-wayland2 1.0.2 shows
   every busy sample of the client's main thread in the `glFinish()` fallback:

   ```
   #4  clock_gettime () from /lib/libsys.so.7
   #5-#10 ?? () from /usr/local/lib/libnvidia-eglcore.so.1
   #11 SyncRendering (...) at src/wayland/wayland-surface.c:1280
   #12 eplWlSwapBuffers (...) at src/wayland/wayland-surface.c:1367
   #13 HookSwapBuffersWithDamage (...) at src/base/platform-base.c:1114
   #14 HookSwapBuffers (...) at src/base/platform-base.c:1152
   #15-#16 libEGL_nvidia.so.0
   #17 QtWaylandClient::QWaylandGLContext::swapBuffers
   ```

   egl-wayland2 sets `supports_implicit_sync = false` when the server runs on
an
   NVIDIA device (`wayland-display.c:1015`). With no syncobj protocol
available,
   `SyncRendering()` has no option except a CPU wait. The egl-wayland2
   maintainers have reviewed this path (NVIDIA/egl-wayland2#64).

## Steps to reproduce

1. Plasma Wayland session on FreeBSD (any GPU whose DRM driver reports
   `DRM_CAP_SYNCOBJ_TIMELINE`).
2. `WAYLAND_DEBUG=1 weston-info` (or any client) and look for
   `wp_linux_drm_syncobj_manager_v1`: it is not listed.
3. On NVIDIA: run a Qt 6 `QOpenGLWidget` app that redraws every frame and
   compare its CPU time (`procstat -r <pid>` over 10 s) with the same app on
   Plasma X11.

## Suggested fix

The 6.6 check exists to make sure `DRM_IOCTL_SYNCOBJ_EVENTFD` is available. The
other check, for 6.6.0–6.6.18 and 6.7, covers specific broken Linux releases.
Neither one means anything on a non-Linux kernel. Options:

- Run the version checks only when the system is Linux. On other systems, rely
  on `supportsSyncObjTimelines()`.
- Or, more generally, probe the ioctl at runtime: call `drmSyncobjEventfd()` on
  handle 0. A kernel that implements the ioctl fails with `ENOENT` (verified on
  FreeBSD above). A kernel without it rejects the unknown ioctl with `EINVAL`.
  The broken-releases check on Linux would remain.

I can test a patch on this setup.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to