The EGL importer — the head of the CUDA/NVENC zero-copy path — opened
`/dev/dri/renderD128` and hoped. On a single-GPU host that is the
NVIDIA node and it always worked. On a hybrid laptop the iGPU is bound
first, so renderD128 is Intel: we built a GBM device on Mesa, asked it
for a pbuffer-capable OpenGL config, got none (Mesa's GBM platform
advertises only window-capable ones — gbm_surface is the point of that
platform there), and reported
zerocopy worker init failed: no EGL config for OpenGL
on a machine whose NVIDIA EGL stack was demonstrably fine, naming
neither the device nor the reason. `PUNKTFUNK_RENDER_NODE` was no
escape either: this path never read it.
Pick the node by what it is — the first `/dev/dri/renderD*` whose
sysfs PCI vendor is 0x10de, the same identification the crate's Vulkan
bridge already uses for its physical device. A local scan rather than a
`pf_gpu` dependency, because this crate is a leaf whose worker is its
own process, and `pf_gpu::linux_render_node` answers a different
question anyway: it follows the operator's GPU *preference*, which may
legitimately name the iGPU. What is needed here is not which GPU to use
but where CUDA is. `PUNKTFUNK_ZEROCOPY_RENDER_NODE` overrides, and no
NVIDIA node found keeps the historical guess — sysfs may just not be
mounted, and the CUDA context is what properly fails on a host with no
NVIDIA at all.
Then stop the config query being able to fail this way: retry without
the surface-type constraint, which is honest because we never create an
EGLSurface — `eglMakeCurrent` runs surfaceless. And name the node in
every error and in the ready line, so the next hybrid host diagnoses
itself.
37 lines
1.9 KiB
TOML
37 lines
1.9 KiB
TOML
# The Linux GPU zero-copy plumbing (plan §9 / §W6), extracted into a leaf crate so the shared
|
|
# frame vocabulary (pf-frame `FramePayload::Cuda`), the encode backends (CUDA copies/context),
|
|
# and the capture import machinery can all reach it WITHOUT the host orchestrator in between.
|
|
# Content is Linux-only; the crate compiles to an empty lib elsewhere so dependents can carry a
|
|
# plain (non-target-gated) dependency.
|
|
[package]
|
|
name = "pf-zerocopy"
|
|
version.workspace = true
|
|
edition = "2021"
|
|
# Inherit the workspace MSRV: clippy keys MSRV-gated lints off it (without this, e.g.
|
|
# `manual_is_multiple_of` fires on code the host crate compiles clean).
|
|
rust-version.workspace = true
|
|
license = "MIT OR Apache-2.0"
|
|
description = "punktfunk host Linux zero-copy GPU plumbing: CUDA context/buffers, EGL/Vulkan dmabuf import, the isolated import worker, and dmabuf implicit-fence sync."
|
|
publish = false
|
|
|
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
anyhow = "1"
|
|
tracing = "0.1"
|
|
libc = "0.2"
|
|
# `libcuda.so.1` is dlopen'd at runtime (NOT link-time) so one Linux binary runs on NVIDIA
|
|
# (zero-copy via CUDA) AND on AMD/Intel (VAAPI, no NVIDIA driver present) — see `cuda::ffi`.
|
|
libloading = "0.8"
|
|
# EGL imports the PipeWire dmabuf, CUDA maps it (`dynamic` = load the NVIDIA libEGL at runtime).
|
|
khronos-egl = { version = "6", features = ["dynamic"] }
|
|
# Vulkan bridge for LINEAR dmabufs (gamescope): VK_EXT_external_memory_dma_buf import,
|
|
# GPU-copy into an exportable allocation, export OPAQUE_FD → cuImportExternalMemory.
|
|
ash = "0.38"
|
|
# The isolated import worker's control protocol: small serde_json blobs over a Unix socket
|
|
# (SCM_RIGHTS carries the fds; pixels never cross the socket).
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
|
|
# Linux-only like the code under test: the render-node scan is exercised against a fixture tree.
|
|
[target.'cfg(target_os = "linux")'.dev-dependencies]
|
|
tempfile = "3"
|