Components: CompositorServer, VulkanBackend
This document explains how Goggles shares GPU textures from the nested compositor to the render backend using Linux DMA-BUF with DRM format modifiers and explicit sync (wp_linux_drm_syncobj_v1).
Key Technologies:
- DMA-BUF: Linux kernel mechanism for sharing GPU buffers between components
- DRM Format Modifiers: Metadata describing GPU-specific memory layouts (tiling, compression)
- Explicit Sync (wp_linux_drm_syncobj_v1): GPU-to-GPU synchronization without CPU polling
flowchart TB
subgraph Goggles["Goggles process"]
App["Target application"]
Compositor["CompositorServer (wlroots headless)"]
Backend["VulkanBackend (DMA-BUF import)"]
Chain["FilterChain"]
Present["Viewer swapchain present"]
App -->|"Wayland surface commit"| Compositor
Compositor -->|"DMA-BUF + explicit sync fence"| Backend
Backend --> Chain --> Present
end
GPU memory is not always laid out linearly. Modern GPUs use various tiling patterns and compression schemes:
- Linear: Simple row-major layout
- Tiled: GPU-specific tile patterns (AMD 64KB tiles, Intel Y-tiling)
- Compressed: Delta Color Compression (DCC), etc.
When sharing GPU buffers, both sides must agree on the memory layout. DRM format modifiers are 64-bit values that encode the exact memory layout:
| Modifier Value | Meaning |
|---|---|
0x0 |
DRM_FORMAT_MOD_LINEAR (universal) |
0x200000020801b04 |
AMD vendor-specific tiling |
0x100000000000001 |
Intel Y-tiling |
By exchanging the modifier value, both sides can create compatible images.
Export (CompositorServer):
- wlroots allocates surface buffer with DRM format modifier support
- Driver selects optimal modifier for the surface format
- Surface buffer is exported as a DMA-BUF file descriptor
- Compositor extracts format, dimensions, stride, and modifier from buffer metadata
- Packages as
ExternalImageFramewith acquire sync fence fromwp_linux_drm_syncobj_v1
Import (VulkanBackend):
- Receive
ExternalImageFramefrom compositor - Create image with explicit modifier (matching compositor's buffer layout)
- Query dedicated allocation requirements (vendor modifiers often require it)
- Import memory via
VkImportMemoryFdInfoKHR - Bind memory and create image view for shader sampling
- Wait on acquire fence before sampling
| Extension | Purpose |
|---|---|
VK_EXT_image_drm_format_modifier |
Create images with modifier tiling |
VK_KHR_image_format_list |
Required dependency for modifier ext |
VK_KHR_external_memory_fd |
Import memory from file descriptor |
VK_EXT_external_memory_dma_buf |
DMA-BUF handle type support |
| Error | Cause | Solution |
|---|---|---|
VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT |
Invalid plane layout (e.g., rowPitch = 0) |
Use explicit modifier with correct stride from compositor metadata. |
requiresDedicatedAllocation validation error |
Vendor modifiers require dedicated allocation | Query VkMemoryDedicatedRequirements and add VkMemoryDedicatedAllocateInfo. |
| Format doesn't support LINEAR tiling | Some formats incompatible with LINEAR + certain usage | Use DRM format modifiers instead of hardcoded LINEAR. |
Explicit sync replaces CPU-polling synchronization with GPU-native fence passing.
Implicit sync relies on the kernel to track buffer usage, which can miss cross-driver or cross-queue dependencies. Explicit sync passes GPU timeline points directly:
- Acquire fence: Compositor signals when the surface buffer is ready for sampling
- Release fence: VulkanBackend signals when rendering is complete and the buffer can be reused
| Fence | Signaled By | Waited On By | Purpose |
|---|---|---|---|
| Acquire fence | CompositorServer | VulkanBackend | Frame buffer ready for shader sampling |
| Release fence | VulkanBackend | CompositorServer | Render complete; buffer safe for reuse |
Synchronization flow:
sequenceDiagram
participant Compositor as CompositorServer
participant Backend as VulkanBackend
Compositor->>Compositor: Surface commit received
Compositor->>Compositor: Export DMA-BUF + acquire fence
Compositor->>Backend: ExternalImageFrame (fd + fence)
Backend->>Backend: Wait on acquire fence (GPU)
Backend->>Backend: Import + sample frame
Backend-->>Compositor: Signal release fence