refactor(host/W6.2): extract the Linux zero-copy GPU plumbing into the pf-zerocopy leaf crate

linux/zerocopy/* (CUDA context/buffers + EGL/Vulkan dmabuf import + the isolated
import worker) and linux/dmabuf_fence.rs move wholesale into crates/pf-zerocopy,
so the coming pf-frame vocabulary crate (FramePayload::Cuda owns a DeviceBuffer)
and the pf-encode/pf-capture subsystem crates can reach the GPU plumbing without
the host orchestrator in between (plan §W6). Content stays Linux-only; the crate
compiles to an empty lib elsewhere, so dependents carry a plain dependency.

drm_fourcc deliberately does NOT move: it consumes the frame vocabulary
(PixelFormat), which sits ABOVE pf-zerocopy — it lives with capture for now and
moves into pf-frame next. cuda's ffi re-export bumps pub(crate)->pub (the raw
CUdeviceptr vocabulary is consumed across the crate boundary by the encode
backends). A crate::zerocopy shim module keeps every existing path valid until
capture/encode themselves move out.

Verified: Linux clippy -D warnings (pf-zerocopy --all-targets + host
nvenc,vulkan-encode,pyrowave --all-targets) + 17/17 pf-zerocopy tests + 321/321
host tests; Windows clippy nvenc,amf-qsv --all-targets Finished exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 09:41:15 +02:00
parent 6ea036766a
commit 85bc5b9a3f
19 changed files with 111 additions and 25 deletions
+24
View File
@@ -55,6 +55,30 @@ impl PixelFormat {
}
}
/// DRM FourCC for a packed 32-bit format name (little-endian, e.g. `b"XR24"`).
#[cfg(target_os = "linux")]
const fn drm_fourcc_code(c: &[u8; 4]) -> u32 {
(c[0] as u32) | ((c[1] as u32) << 8) | ((c[2] as u32) << 16) | ((c[3] as u32) << 24)
}
/// Map a SPA/our [`PixelFormat`] to the DRM FourCC EGL expects for import. SPA byte order `BGRx`
/// ⇒ DRM `XRGB8888` (memory B,G,R,X), etc. Lives with the frame vocabulary (not in
/// `pf-zerocopy`) because it consumes [`PixelFormat`], which sits above that crate.
#[cfg(target_os = "linux")]
pub fn drm_fourcc(format: PixelFormat) -> Option<u32> {
use PixelFormat::*;
Some(match format {
Bgrx => drm_fourcc_code(b"XR24"), // DRM_FORMAT_XRGB8888
Bgra => drm_fourcc_code(b"AR24"), // DRM_FORMAT_ARGB8888
Rgbx => drm_fourcc_code(b"XB24"), // DRM_FORMAT_XBGR8888
Rgba => drm_fourcc_code(b"AB24"), // DRM_FORMAT_ABGR8888
// 24-bit packed RGB/BGR have no straightforward dmabuf import here; use the CPU path.
// Rgb10a2/Nv12/P010 are the Windows HDR / video-processor formats — never produced on
// Linux; Yuv444 is OUR convert's OUTPUT, never a capture source format.
Rgb | Bgr | Rgb10a2 | Nv12 | P010 | Yuv444 => return None,
})
}
/// What a Windows capturer should produce, resolved **once** per session and passed **into**
/// [`capture_virtual_output`] (Goal-1 stage 5, plan §2.3/§5). Passing the format in is what lets a
/// capturer stop re-deriving the encode backend itself — it kills the