Target.init now picks a modifier by intersecting two channels:
- the GPU's supported modifiers for `format` with COLOR_ATTACHMENT |
TRANSFER_SRC | SAMPLED feature bits (filtered to single plane);
- the compositor's accepted modifiers, fetched via a new
ghostty_platform_vulkan_s.get_supported_modifiers callback.
First non-LINEAR hit wins (vendor-tiled is the perf path on every
modern GPU); LINEAR is the fallback; legacy_copy stays the floor.
NVIDIA RTX 2080 + Vulkan 1.4.329 verified: Target now picks
DRM_FORMAT_MOD_NVIDIA_* (0x300000000606015), Target.tiling=.direct,
image_backed=1, dmabuf flows through wl_subsurface without
protocol errors. Where Phase 1 left NVIDIA at legacy_copy + QImage,
this lands the full zero-copy path.
The new callback's data source is the zwp_linux_dmabuf_v1 format/
modifier events. SubsurfacePresenter.cpp's globals discovery now
listens for those events during its private-queue roundtrip (two
roundtrips: bind, then collect events) and caches them in a
process-wide (format → modifiers) table. Host::instance() eagerly
primes this on the GUI thread so the renderer-thread callback is a
lock-free read of an immutable map.
Renderer changes:
- Target.pickModifier replaces the LINEAR-only probe; intersects
host ∩ GPU, preferring non-LINEAR single-plane modifiers.
- Target.initDirect now switches create-info variants by chosen
modifier: EXPLICIT for LINEAR (we know rowPitch), LIST for
vendor-tiled (driver picks opaque layout, we query back via
vkGetImageDrmFormatModifierPropertiesEXT and vkGetImageSubresourceLayout).
- Direct-mode memory switches to DEVICE_LOCAL — image_backed=true
means the host won't mmap, so we no longer need HOST_VISIBLE
(and many drivers won't expose HOST_VISIBLE bits for tiled
exportable images anyway).
- Device.zig adds vkGetImageDrmFormatModifierPropertiesEXT and
vkGetPhysicalDeviceFormatProperties2 to the dispatch table.
Host changes:
- qt/src/vulkan/Host.cpp adds VK_EXT_image_drm_format_modifier to
kRequiredDeviceExtensions so the device-level proc-addr lookup
for vkGetImageDrmFormatModifierPropertiesEXT actually resolves.
- wl_compositor bound at version min(advertised, 6) so the child
wl_surface supports set_buffer_scale (added in v3). Guarded the
set_buffer_scale call by wl_proxy_get_version for older
compositors.
Co-Authored-By: claude-flow <ruv@ruv.net>