ADR 0003 — Vulkan presentation through DMA-BUF
Status: accepted
Decision
NeferGUI renders with Vulkan into exportable images and presents them as zwp_linux_dmabuf_v1 buffers. It does not use VK_KHR_swapchain.
- Synchronization uses
wp_linux_drm_syncobj_v1with Vulkan timeline semaphores. There is no CPU-fence fallback. - The Vulkan physical device must match the
main_deviceof linux-dmabuf feedback. There is no cross-GPU fallback. - Formats: one-plane
XRGB8888for opaque windows (default) andARGB8888for transparent windows, both mapped toVK_FORMAT_B8G8R8A8_UNORM, with a modifier supported by both the compositor and the GPU. - Three exportable images per window.
- Shaders are GLSL compiled by
glslcthroughgo generate. SPIR-V is committed and embedded; consumers do not needglslc.
Buffer lifecycle
Available → Rendering → acquire point exported → committed with acquire/release points
→ compositor reads → release point of its latest commit reached → Available
While a wp_linux_drm_syncobj_surface_v1 exists, wl_buffer.release delivery is undefined (linux-drm-syncobj-v1). A buffer is reused only after the release point set for its most recent commit is signaled; each buffer has its own release timeline because points may signal out of order. wl_buffer.release is traced when it arrives but never gates reuse. Frame callbacks schedule drawing; they never authorize reuse.
The UI loop never blocks in Wayland dispatch while GPU or compositor completion is pending. Blocking sources (Wayland socket, release timeline waits) run on their own goroutines and only post events to the loop, which owns all presentation state. Resize creates a new generation; old images are retired after their latest release point signals.
At shutdown, release points protect reuse of contents, not the lifetime of exported DMA-BUF memory: kernel FD references and compositor imports are independent of the client's Vulkan allocation. Detach and commit null, destroy the syncobj surface, wait at most 200 ms for outstanding release points for tracing, wait for client GPU completion, destroy wl_buffers and all client images/memory/semaphores/syncobj handles, then destroy the device. Never abandon Vulkan allocations solely because a compositor release point has not arrived.
Opaque() sets a full-surface opaque region. Transparent() uses premultiplied alpha and no opaque region. Background blur is a compositor setting, not a NeferGUI feature.