gpu-video-encoder: VAAPI driver retry, Vello-capable device, Send
Three fixes found while running the zero-copy export on real Intel hardware: - vaapi::create_device() retries LIBVA_DRIVER_NAME in order iHD -> auto -> i965 -> radeonsi. libva was auto-selecting the legacy i965 driver, which fails on newer Intel GPUs; the modern iHD (intel-media-driver) is needed. encoder.rs now builds its hwdevice through this helper. - vk_device: request the adapter's full limits instead of downlevel_defaults. Vello's compute pipelines need max_storage_buffers_per_shader_stage >= 5 (downlevel caps at 4), which panicked Vello's shader init on the export device. This device only ever runs on a real VAAPI GPU. - ZeroCopyEncoder: unsafe impl Send. It owns its FFmpeg/Vulkan handles exclusively and is only moved (onto the export thread), never shared.
This commit is contained in:
parent
3e4f29c297
commit
2bce5e93a6
|
|
@ -35,6 +35,10 @@ pub struct ZeroCopyEncoder {
|
|||
cache: HashMap<usize, ImportedNv12>,
|
||||
}
|
||||
|
||||
// The encoder owns its FFmpeg contexts (raw `*mut`) and Vulkan/wgpu handles exclusively; it is
|
||||
// never shared, only moved. Sending it to a dedicated export thread is sound.
|
||||
unsafe impl Send for ZeroCopyEncoder {}
|
||||
|
||||
impl ZeroCopyEncoder {
|
||||
/// Build a zero-copy `h264_vaapi` encoder writing to `output_path` (container inferred
|
||||
/// from the extension, e.g. `.mp4`). `Err` if VAAPI/the device is unavailable.
|
||||
|
|
@ -48,18 +52,7 @@ impl ZeroCopyEncoder {
|
|||
let drm = vk_device::create()?;
|
||||
let renderer = Rgba2Nv12::new(&drm.device);
|
||||
unsafe {
|
||||
let mut hw_device: *mut ff::AVBufferRef = ptr::null_mut();
|
||||
let node = CString::new("/dev/dri/renderD128").unwrap();
|
||||
if ff::av_hwdevice_ctx_create(
|
||||
&mut hw_device,
|
||||
ff::AVHWDeviceType::AV_HWDEVICE_TYPE_VAAPI,
|
||||
node.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
) < 0
|
||||
{
|
||||
return Err("av_hwdevice_ctx_create failed".into());
|
||||
}
|
||||
let mut hw_device = crate::vaapi::create_device()?;
|
||||
let name = CString::new("h264_vaapi").unwrap();
|
||||
let codec = ff::avcodec_find_encoder_by_name(name.as_ptr());
|
||||
if codec.is_null() {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,48 @@ fn averror(e: i32) -> i32 {
|
|||
-e
|
||||
}
|
||||
|
||||
/// Create a VAAPI hwdevice on `/dev/dri/renderD128`, trying driver names in turn.
|
||||
///
|
||||
/// libva's auto-selection can pick a driver that doesn't support the GPU — notably it
|
||||
/// chooses the legacy `i965` driver on newer Intel parts (Gen 11+) where the modern `iHD`
|
||||
/// driver is required. Each `av_hwdevice_ctx_create` opens a fresh VADisplay, so
|
||||
/// `LIBVA_DRIVER_NAME` is re-read per attempt. We try `iHD` first (modern Intel), then the
|
||||
/// caller's original setting, then `i965` (older Intel) and `radeonsi` (AMD). On success the
|
||||
/// working driver name is left in the env; on total failure the original value is restored.
|
||||
pub fn create_device() -> Result<*mut ff::AVBufferRef, String> {
|
||||
unsafe {
|
||||
let node = CString::new("/dev/dri/renderD128").unwrap();
|
||||
let original = std::env::var_os("LIBVA_DRIVER_NAME");
|
||||
let attempts: [Option<&str>; 4] = [Some("iHD"), None, Some("i965"), Some("radeonsi")];
|
||||
for drv in attempts {
|
||||
match drv {
|
||||
Some(d) => std::env::set_var("LIBVA_DRIVER_NAME", d),
|
||||
// `None` = the caller's original setting (or libva auto if unset).
|
||||
None => match &original {
|
||||
Some(v) => std::env::set_var("LIBVA_DRIVER_NAME", v),
|
||||
None => std::env::remove_var("LIBVA_DRIVER_NAME"),
|
||||
},
|
||||
}
|
||||
let mut hw: *mut ff::AVBufferRef = ptr::null_mut();
|
||||
if ff::av_hwdevice_ctx_create(
|
||||
&mut hw,
|
||||
ff::AVHWDeviceType::AV_HWDEVICE_TYPE_VAAPI,
|
||||
node.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
) >= 0
|
||||
{
|
||||
return Ok(hw);
|
||||
}
|
||||
}
|
||||
match &original {
|
||||
Some(v) => std::env::set_var("LIBVA_DRIVER_NAME", v),
|
||||
None => std::env::remove_var("LIBVA_DRIVER_NAME"),
|
||||
}
|
||||
Err("av_hwdevice_ctx_create(VAAPI) failed for all drivers (iHD/i965/radeonsi)".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy tight NV12 (`Y` then interleaved `UV`) into an AVFrame's planes, respecting
|
||||
/// each plane's linesize (which FFmpeg may pad).
|
||||
unsafe fn fill_nv12(frame: *mut ff::AVFrame, nv12: &[u8], width: u32, height: u32) {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,10 @@ unsafe fn create_inner() -> Result<DrmDevice, String> {
|
|||
&wgpu::DeviceDescriptor {
|
||||
label: Some("drm-import-device"),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::downlevel_defaults(),
|
||||
// Vello's compute pipelines need more than downlevel limits (e.g.
|
||||
// max_storage_buffers_per_shader_stage >= 5). This device only ever runs on a
|
||||
// real VAAPI-capable GPU, so request the adapter's full limits.
|
||||
required_limits: wgpu_adapter.limits(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue