Problem
On the NVIDIA proprietary driver (nvidia-drm), KMS refuses the hardware cursor plane:
{"level":"warn","component":"drm","error":"invalid argument","connector":"DP-1","message":"cursor plane refused; hardware cursor off"}
NeferWL then falls back to a software cursor drawn into the frame. It works, but:
- every pointer motion forces a new frame (more GPU work, more latency);
- the cursor only appears after the first motion.
AMD (amdgpu) does not hit this: the cursor plane is accepted.
Likely cause
The cursor buffers are linear images allocated by Vulkan and exported (internal/adapters/vulkan/cursor.go, CursorBuffers), the same allocate-in-Vulkan, scan-out-in-KMS path that corrupted the primary plane on NVIDIA. nvidia-drm has its own cursor buffer requirements (Aquamarine notes NVIDIA cursor buffers may be non-renderable or linear-only).
What other compositors do
- wlroots: allocates cursor buffers with GBM using
GBM_BO_USE_CURSOR. - Hyprland:
cursor:use_cpu_buffer(default on NVIDIA) writes the cursor into a CPU (dumb) buffer.
Proposed fix
- Allocate the two cursor buffers with GBM (
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE, linear ARGB8888) using the existinginternal/adapters/drm/gbmpackage. Write the pixels withgbm_bo_writeor a map. - Otherwise, use KMS dumb buffers (
DRM_IOCTL_MODE_CREATE_DUMBand mmap) and write the cursor pixels from the CPU (64×64, negligible cost). - Keep the current Vulkan cursor images, then the software cursor, as fallbacks.
- Log which cursor allocator is used.
Verification
- Unit tests with generated mocks for the allocator choice and fallbacks.
- Allocation test on a real NVIDIA GPU (render node only; no display available for the scanout itself).
- End-to-end check on an NVIDIA machine with a display: no
cursor plane refusedwarning, and the cursor shows at startup.