From d7e6da12ace2ab495cf04ce617a36bf4e6e1994e Mon Sep 17 00:00:00 2001 From: Kristian Ollikainen <14197772+DatCaptainHorse@users.noreply.github.com> Date: Tue, 20 May 2025 08:50:24 +0300 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=20feat(runner):=20DMA-BUF=20support?= =?UTF-8?q?=20for=20Intel/AMD=20GPUs=20(#283)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Adds DMA-BUF support for non-NVIDIA GPUs using GL elements as conversion workaround. Tested with QSV and VA encoders, note that H.264 seems to only work for QSV encoder, for `vah264(lp)enc` theres major CPU usage with DMA-BUF enabled. Don't mind the branch name, I was working on relay before and changed gears to runner after noticing some DMA-BUF stuff :sweat_smile: ## Summary by CodeRabbit - **Chores** - Added a `.dockerignore` file to exclude the `target` directory from Docker builds. - Updated `.gitignore` to ignore the `target` directory. - **New Features** - Enhanced video processing pipeline with updated handling of DMA-BUF support, including improved compatibility for different GPU vendors and refined video element configurations. --------- Co-authored-by: DatCaptainHorse --- packages/server/.dockerignore | 1 + packages/server/.gitignore | 3 +- packages/server/src/main.rs | 59 +++++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 21 deletions(-) create mode 100644 packages/server/.dockerignore diff --git a/packages/server/.dockerignore b/packages/server/.dockerignore new file mode 100644 index 00000000..9f970225 --- /dev/null +++ b/packages/server/.dockerignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/packages/server/.gitignore b/packages/server/.gitignore index a53d9628..eec9534d 100644 --- a/packages/server/.gitignore +++ b/packages/server/.gitignore @@ -1 +1,2 @@ -*.mp4 \ No newline at end of file +*.mp4 +target/ \ No newline at end of file diff --git a/packages/server/src/main.rs b/packages/server/src/main.rs index b1e1edf1..4206fc7d 100644 --- a/packages/server/src/main.rs +++ b/packages/server/src/main.rs @@ -172,7 +172,7 @@ fn handle_encoder_audio(args: &args::Args) -> String { #[tokio::main] async fn main() -> Result<(), Box> { // Parse command line arguments - let mut args = args::Args::new(); + let args = args::Args::new(); if args.app.verbose { args.debug_print(); } @@ -206,10 +206,10 @@ async fn main() -> Result<(), Box> { } let gpu = gpu.unwrap(); - // TODO: Currently DMA-BUF only works for NVIDIA - if args.app.dma_buf && *gpu.vendor() != GPUVendor::NVIDIA { - log::warn!("DMA-BUF is currently unsupported outside NVIDIA GPUs, force disabling.."); - args.app.dma_buf = false; + if args.app.dma_buf { + log::warn!( + "DMA-BUF is experimental, it may or may not improve performance, or even work at all." + ); } // Handle video encoder selection @@ -288,7 +288,7 @@ async fn main() -> Result<(), Box> { ))?; caps_filter.set_property("caps", &caps); - // GL Upload Element + // GL Upload element let glupload = gst::ElementFactory::make("glupload").build()?; // GL color convert element @@ -299,6 +299,9 @@ async fn main() -> Result<(), Box> { let gl_caps = gst::Caps::from_str("video/x-raw(memory:GLMemory),format=NV12")?; gl_caps_filter.set_property("caps", &gl_caps); + // GL download element (needed only for DMA-BUF outside NVIDIA GPUs) + let gl_download = gst::ElementFactory::make("gldownload").build()?; + // Video Converter Element let video_converter = gst::ElementFactory::make("videoconvert").build()?; @@ -372,7 +375,11 @@ async fn main() -> Result<(), Box> { // If DMA-BUF is enabled, add glupload, color conversion and caps filter if args.app.dma_buf { - pipeline.add_many(&[&glupload, &glcolorconvert, &gl_caps_filter])?; + if *gpu.vendor() == GPUVendor::NVIDIA { + pipeline.add_many(&[&glupload, &glcolorconvert, &gl_caps_filter])?; + } else { + pipeline.add_many(&[&glupload, &glcolorconvert, &gl_caps_filter, &gl_download])?; + } } // Link main audio branch @@ -389,19 +396,31 @@ async fn main() -> Result<(), Box> { // With DMA-BUF, also link glupload and it's caps if args.app.dma_buf { - // Link video source to caps_filter, glupload, gl_caps_filter, video_converter, video_encoder, webrtcsink - gst::Element::link_many(&[ - &video_source, - &caps_filter, - &video_queue, - &video_clocksync, - &glupload, - &glcolorconvert, - &gl_caps_filter, - &video_encoder, - ])?; + if *gpu.vendor() == GPUVendor::NVIDIA { + gst::Element::link_many(&[ + &video_source, + &caps_filter, + &video_queue, + &video_clocksync, + &glupload, + &glcolorconvert, + &gl_caps_filter, + &video_encoder, + ])?; + } else { + gst::Element::link_many(&[ + &video_source, + &caps_filter, + &video_queue, + &video_clocksync, + &glupload, + &glcolorconvert, + &gl_caps_filter, + &gl_download, + &video_encoder, + ])?; + } } else { - // Link video source to caps_filter, video_converter, video_encoder, webrtcsink gst::Element::link_many(&[ &video_source, &caps_filter, @@ -437,7 +456,7 @@ async fn main() -> Result<(), Box> { let result = run_pipeline(pipeline.clone()).await; match result { - Ok(_) => log::info!("All tasks completed successfully"), + Ok(_) => log::info!("All tasks finished"), Err(e) => { log::error!("Error occurred in one of the tasks: {}", e); return Err("Error occurred in one of the tasks".into());