diff --git a/vhost-device-gpu/CHANGELOG.md b/vhost-device-gpu/CHANGELOG.md index de9ed8e9c..501491109 100644 --- a/vhost-device-gpu/CHANGELOG.md +++ b/vhost-device-gpu/CHANGELOG.md @@ -3,6 +3,8 @@ ### Added +- [https://github.com/rust-vmm/vhost-device/pull/900] vhost-device-gpu: Add support for specifying GPU path + ### Changed ### Fixed diff --git a/vhost-device-gpu/README.md b/vhost-device-gpu/README.md index 6b659d6ab..f8010880d 100644 --- a/vhost-device-gpu/README.md +++ b/vhost-device-gpu/README.md @@ -56,6 +56,9 @@ A virtio-gpu device using the vhost-user protocol. [default: true] [possible values: true, false] + -p, --gpu-path + GPU path (e.g. /dev/dri/renderD128), only available for virglrenderer backend + -h, --help Print help (see a summary with '-h') diff --git a/vhost-device-gpu/src/device.rs b/vhost-device-gpu/src/device.rs index a77fe2cbd..8932d5621 100644 --- a/vhost-device-gpu/src/device.rs +++ b/vhost-device-gpu/src/device.rs @@ -765,6 +765,7 @@ mod tests { GpuMode::VirglRenderer, Some(GpuCapset::VIRGL | GpuCapset::VIRGL2), GpuFlags::default(), + None, ) .unwrap(); let backend = VhostUserGpuBackend::new(config).unwrap(); @@ -1353,7 +1354,7 @@ mod tests { rusty_fork_test! { #[test] fn test_verify_backend() { - let gpu_config = GpuConfig::new(GpuMode::VirglRenderer, None, GpuFlags::default()).unwrap(); + let gpu_config = GpuConfig::new(GpuMode::VirglRenderer, None, GpuFlags::default(), None).unwrap(); let backend = VhostUserGpuBackend::new(gpu_config).unwrap(); assert_eq!(backend.num_queues(), NUM_QUEUES); diff --git a/vhost-device-gpu/src/lib.rs b/vhost-device-gpu/src/lib.rs index f7ab7d6c3..9b9fc2f3b 100644 --- a/vhost-device-gpu/src/lib.rs +++ b/vhost-device-gpu/src/lib.rs @@ -127,6 +127,7 @@ pub struct GpuConfig { gpu_mode: GpuMode, capset: GpuCapset, flags: GpuFlags, + gpu_path: Option, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -198,6 +199,7 @@ impl GpuConfig { gpu_mode: GpuMode, capset: Option, flags: GpuFlags, + gpu_path: Option, ) -> Result { let capset = capset.unwrap_or_else(|| Self::get_default_capset_for_mode(gpu_mode)); Self::validate_capset(gpu_mode, capset)?; @@ -211,6 +213,7 @@ impl GpuConfig { gpu_mode, capset, flags, + gpu_path, }) } @@ -263,7 +266,8 @@ mod tests { #[test] fn test_gpu_config_create_default_virglrenderer() { - let config = GpuConfig::new(GpuMode::VirglRenderer, None, GpuFlags::new_default()).unwrap(); + let config = + GpuConfig::new(GpuMode::VirglRenderer, None, GpuFlags::new_default(), None).unwrap(); assert_eq!(config.gpu_mode(), GpuMode::VirglRenderer); assert_eq!(config.capsets(), GpuConfig::DEFAULT_VIRGLRENDER_CAPSET_MASK); } @@ -271,14 +275,14 @@ mod tests { #[test] #[cfg(feature = "gfxstream")] fn test_gpu_config_create_default_gfxstream() { - let config = GpuConfig::new(GpuMode::Gfxstream, None, GpuFlags::default()).unwrap(); + let config = GpuConfig::new(GpuMode::Gfxstream, None, GpuFlags::default(), None).unwrap(); assert_eq!(config.gpu_mode(), GpuMode::Gfxstream); assert_eq!(config.capsets(), GpuConfig::DEFAULT_GFXSTREAM_CAPSET_MASK); } #[cfg(feature = "gfxstream")] fn assert_invalid_gpu_config(mode: GpuMode, capset: GpuCapset, expected_capset: GpuCapset) { - let result = GpuConfig::new(mode, Some(capset), GpuFlags::new_default()); + let result = GpuConfig::new(mode, Some(capset), GpuFlags::new_default(), None); assert_matches!( result, Err(GpuConfigError::CapsetUnsupportedByMode( @@ -294,6 +298,7 @@ mod tests { GpuMode::VirglRenderer, Some(GpuCapset::VIRGL2), GpuFlags::default(), + None, ) .unwrap(); assert_eq!(config.gpu_mode(), GpuMode::VirglRenderer); @@ -323,7 +328,7 @@ mod tests { use_gles: false, ..GpuFlags::new_default() }; - let result = GpuConfig::new(GpuMode::Gfxstream, Some(capset), flags); + let result = GpuConfig::new(GpuMode::Gfxstream, Some(capset), flags, None); assert_matches!(result, Err(GpuConfigError::GlesRequiredByGfxstream)); } @@ -355,7 +360,8 @@ mod tests { fn test_fail_listener() { // This will fail the listeners and thread will panic. let socket_name = Path::new("/proc/-1/nonexistent"); - let config = GpuConfig::new(GpuMode::VirglRenderer, None, GpuFlags::default()).unwrap(); + let config = + GpuConfig::new(GpuMode::VirglRenderer, None, GpuFlags::default(), None).unwrap(); assert_matches!( start_backend(socket_name, config).unwrap_err(), diff --git a/vhost-device-gpu/src/main.rs b/vhost-device-gpu/src/main.rs index 0d00b1172..477d33f88 100644 --- a/vhost-device-gpu/src/main.rs +++ b/vhost-device-gpu/src/main.rs @@ -63,6 +63,11 @@ pub struct GpuArgs { #[clap(flatten)] pub flags: GpuFlagsArgs, + + /// GPU path (e.g. /dev/dri/renderD128), only available for + /// virglrenderer backend. + #[clap(short = 'p', long, value_name = "PATH")] + pub gpu_path: Option, } #[derive(Parser, Debug)] @@ -115,7 +120,7 @@ impl From for GpuFlags { pub fn config_from_args(args: GpuArgs) -> Result<(PathBuf, GpuConfig), GpuConfigError> { let flags = GpuFlags::from(args.flags); let capset = args.capset.map(capset_names_into_capset); - let config = GpuConfig::new(args.gpu_mode, capset, flags)?; + let config = GpuConfig::new(args.gpu_mode, capset, flags, args.gpu_path)?; Ok((args.socket_path, config)) } @@ -186,6 +191,7 @@ mod tests { use_gles: false, use_surfaceless: false, }, + gpu_path: None, }; let (socket_path, config) = config_from_args(args).unwrap(); diff --git a/vhost-device-gpu/src/virtio_gpu.rs b/vhost-device-gpu/src/virtio_gpu.rs index d2d46f318..d0ed8560d 100644 --- a/vhost-device-gpu/src/virtio_gpu.rs +++ b/vhost-device-gpu/src/virtio_gpu.rs @@ -7,7 +7,9 @@ use std::{ collections::BTreeMap, io::IoSliceMut, os::fd::{AsFd, FromRawFd, RawFd}, + path::PathBuf, result::Result, + str::FromStr, sync::{Arc, Mutex}, }; @@ -16,7 +18,8 @@ use log::{debug, error, trace, warn}; use rutabaga_gfx::{ Resource3DInfo, ResourceCreate3D, ResourceCreateBlob, Rutabaga, RutabagaBuilder, RutabagaComponentType, RutabagaFence, RutabagaFenceHandler, RutabagaHandle, - RutabagaIntoRawDescriptor, RutabagaIovec, Transfer3D, RUTABAGA_HANDLE_TYPE_MEM_DMABUF, + RutabagaIntoRawDescriptor, RutabagaIovec, RutabagaPath, Transfer3D, + RUTABAGA_HANDLE_TYPE_MEM_DMABUF, RUTABAGA_PATH_TYPE_GPU, }; #[cfg(feature = "gfxstream")] use vhost::vhost_user::gpu_message::VhostUserGpuScanout; @@ -403,7 +406,7 @@ impl RutabagaVirtioGpu { GpuMode::Gfxstream => RutabagaComponentType::Gfxstream, }; - let builder = RutabagaBuilder::new(gpu_config.capsets().bits(), fence) + let mut builder = RutabagaBuilder::new(gpu_config.capsets().bits(), fence) .set_use_egl(gpu_config.flags().use_egl) .set_use_gles(gpu_config.flags().use_gles) .set_use_surfaceless(gpu_config.flags().use_surfaceless) @@ -411,6 +414,18 @@ impl RutabagaVirtioGpu { // could work, so this is always enabled .set_use_external_blob(true); + let mut rutabaga_paths = Vec::new(); + if let Some(gpu_path) = gpu_config.gpu_path.as_ref() { + rutabaga_paths.push(RutabagaPath { + // PathBuf::from_str() never fails + path: PathBuf::from_str(gpu_path).unwrap(), + path_type: RUTABAGA_PATH_TYPE_GPU, + }); + } + if !rutabaga_paths.is_empty() { + builder = builder.set_rutabaga_paths(Some(rutabaga_paths)); + } + (builder, component) } @@ -1155,7 +1170,7 @@ mod tests { _ => panic!("Unsupported component type for test"), }; - let config = GpuConfig::new(gpu_mode, capsets, GpuFlags::default()).unwrap(); + let config = GpuConfig::new(gpu_mode, capsets, GpuFlags::default(), None).unwrap(); // Mock memory let mem = GuestMemoryAtomic::new(