mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-28 17:44:10 +00:00
crosvm: move gpu arg parsing related code into sys/unix
windows parses gpu code quite differently. The cl also move some unix only(because they expect the file /dev/kvm to be around) tests. BUG=b:213146388 TEST=presubmit Change-Id: I1f9b11485e09808f4748c8b49d0bc8b29e8ca525 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3732374 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Vikram Auradkar <auradkar@google.com>
This commit is contained in:
parent
ed071b6edd
commit
88b3f563f8
3 changed files with 719 additions and 696 deletions
|
@ -13,6 +13,8 @@ use super::platform::GpuRenderServerParameters;
|
|||
use super::sys::config::parse_coiommu_params;
|
||||
#[cfg(all(feature = "gpu", feature = "virgl_renderer_next"))]
|
||||
use super::sys::config::parse_gpu_render_server_options;
|
||||
#[cfg(feature = "gpu")]
|
||||
use super::sys::config::{parse_gpu_display_options, parse_gpu_options};
|
||||
|
||||
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
|
||||
use super::config::parse_video_options;
|
||||
|
|
|
@ -1324,350 +1324,6 @@ pub fn parse_stub_pci_parameters(s: &str) -> Result<StubPciParameters, String> {
|
|||
Ok(params)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[derive(Default)]
|
||||
struct GpuDisplayParametersBuilder {
|
||||
width: Option<u32>,
|
||||
height: Option<u32>,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
impl GpuDisplayParametersBuilder {
|
||||
fn parse(&mut self, arg: &str) -> argument::Result<()> {
|
||||
let mut kv = arg.split('=');
|
||||
let k = kv.next().unwrap_or("");
|
||||
let v = kv.next().unwrap_or("");
|
||||
match k {
|
||||
"width" => {
|
||||
let width = v
|
||||
.parse::<u32>()
|
||||
.map_err(|_| argument::Error::InvalidValue {
|
||||
value: v.to_string(),
|
||||
expected: String::from("gpu parameter 'width' must be a valid integer"),
|
||||
})?;
|
||||
self.width = Some(width);
|
||||
}
|
||||
"height" => {
|
||||
let height = v
|
||||
.parse::<u32>()
|
||||
.map_err(|_| argument::Error::InvalidValue {
|
||||
value: v.to_string(),
|
||||
expected: String::from("gpu parameter 'height' must be a valid integer"),
|
||||
})?;
|
||||
self.height = Some(height);
|
||||
}
|
||||
_ => {
|
||||
return Err(argument::Error::UnknownArgument(format!(
|
||||
"gpu-display parameter {}",
|
||||
k
|
||||
)))
|
||||
}
|
||||
}
|
||||
self.args.push(arg.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build(&self) -> Result<Option<GpuDisplayParameters>, String> {
|
||||
match (self.width, self.height) {
|
||||
(None, None) => Ok(None),
|
||||
(None, Some(_)) | (Some(_), None) => {
|
||||
let mut value = self
|
||||
.args
|
||||
.clone()
|
||||
.into_iter()
|
||||
.fold(String::new(), |args_so_far, arg| args_so_far + &arg + ",");
|
||||
value.pop();
|
||||
return Err(invalid_value_err(
|
||||
value,
|
||||
"gpu must include both 'width' and 'height' if either is supplied",
|
||||
));
|
||||
}
|
||||
(Some(width), Some(height)) => Ok(Some(GpuDisplayParameters { width, height })),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub fn parse_gpu_options(s: &str) -> Result<GpuParameters, String> {
|
||||
use devices::virtio::GpuMode;
|
||||
use rutabaga_gfx::RutabagaWsi;
|
||||
|
||||
use crate::crosvm::sys::config::is_gpu_backend_deprecated;
|
||||
|
||||
#[cfg(feature = "gfxstream")]
|
||||
let mut vulkan_specified = false;
|
||||
#[cfg(feature = "gfxstream")]
|
||||
let mut syncfd_specified = false;
|
||||
#[cfg(feature = "gfxstream")]
|
||||
let mut angle_specified = false;
|
||||
|
||||
let mut display_param_builder: GpuDisplayParametersBuilder = Default::default();
|
||||
let mut gpu_params = GpuParameters::default();
|
||||
|
||||
for frag in s.split(',') {
|
||||
let mut rest: Option<&str> = None;
|
||||
let mut kv = frag.split('=');
|
||||
let k = kv.next().unwrap_or("");
|
||||
let v = kv.next().unwrap_or("");
|
||||
match k {
|
||||
// Deprecated: Specifying --gpu=<mode> Not great as the mode can be set multiple
|
||||
// times if the user specifies several modes (--gpu=2d,virglrenderer,gfxstream)
|
||||
"2d" | "2D" => {
|
||||
gpu_params.mode = GpuMode::Mode2D;
|
||||
}
|
||||
"3d" | "3D" | "virglrenderer" => {
|
||||
gpu_params.mode = GpuMode::ModeVirglRenderer;
|
||||
}
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"gfxstream" => {
|
||||
gpu_params.mode = GpuMode::ModeGfxstream;
|
||||
}
|
||||
// Preferred: Specifying --gpu,backend=<mode>
|
||||
"backend" => match v {
|
||||
"2d" | "2D" => {
|
||||
if is_gpu_backend_deprecated(v) {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"this backend type is deprecated, please use gfxstream.",
|
||||
));
|
||||
} else {
|
||||
gpu_params.mode = GpuMode::Mode2D;
|
||||
}
|
||||
}
|
||||
"3d" | "3D" | "virglrenderer" => {
|
||||
if is_gpu_backend_deprecated(v) {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"this backend type is deprecated, please use gfxstream.",
|
||||
));
|
||||
} else {
|
||||
gpu_params.mode = GpuMode::ModeVirglRenderer;
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"gfxstream" => {
|
||||
gpu_params.mode = GpuMode::ModeGfxstream;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"gpu parameter 'backend' should be one of (2d|virglrenderer|gfxstream)",
|
||||
#[cfg(not(feature = "gfxstream"))]
|
||||
"gpu parameter 'backend' should be one of (2d|3d)",
|
||||
));
|
||||
}
|
||||
},
|
||||
"egl" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_egl = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_egl = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'egl' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"gles" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_gles = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_gles = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'gles' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"glx" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_glx = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_glx = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'glx' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"surfaceless" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_surfaceless = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_surfaceless = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'surfaceless' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"syncfd" => {
|
||||
syncfd_specified = true;
|
||||
match v {
|
||||
"true" | "" => {
|
||||
gpu_params.gfxstream_use_syncfd = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.gfxstream_use_syncfd = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(argument::Error::InvalidValue {
|
||||
value: v.to_string(),
|
||||
expected: String::from("gpu parameter 'syncfd' should be a boolean"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"angle" => {
|
||||
angle_specified = true;
|
||||
match v {
|
||||
"true" | "" => {
|
||||
gpu_params.gfxstream_use_guest_angle = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.gfxstream_use_guest_angle = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'angle' should be a boolean",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
"vulkan" => {
|
||||
#[cfg(feature = "gfxstream")]
|
||||
{
|
||||
vulkan_specified = true;
|
||||
}
|
||||
match v {
|
||||
"true" | "" => {
|
||||
gpu_params.use_vulkan = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.use_vulkan = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'vulkan' should be a boolean",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
"wsi" => match v {
|
||||
"vk" => {
|
||||
gpu_params.wsi = Some(RutabagaWsi::Vulkan);
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(v, "gpu parameter 'wsi' should be vk"));
|
||||
}
|
||||
},
|
||||
"cache-path" => gpu_params.cache_path = Some(v.to_string()),
|
||||
"cache-size" => gpu_params.cache_size = Some(v.to_string()),
|
||||
"pci-bar-size" => {
|
||||
let size = parse_hex_or_decimal(v).map_err(|_| {
|
||||
"gpu parameter `pci-bar-size` must be a valid hex or decimal value"
|
||||
})?;
|
||||
gpu_params.pci_bar_size = size;
|
||||
}
|
||||
"udmabuf" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.udmabuf = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.udmabuf = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'udmabuf' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"context-types" => {
|
||||
let context_types: Vec<String> = v.split(':').map(|s| s.to_string()).collect();
|
||||
gpu_params.context_mask = rutabaga_gfx::calculate_context_mask(context_types);
|
||||
}
|
||||
"" => {}
|
||||
_ => {
|
||||
rest = Some(frag);
|
||||
}
|
||||
}
|
||||
if let Some(arg) = rest.take() {
|
||||
match display_param_builder.parse(arg) {
|
||||
Ok(()) => {}
|
||||
Err(argument::Error::UnknownArgument(_)) => {
|
||||
rest = Some(arg);
|
||||
}
|
||||
Err(err) => return Err(err.to_string()),
|
||||
}
|
||||
}
|
||||
if let Some(arg) = rest.take() {
|
||||
return Err(format!("unknown gpu parameter {}", arg));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(display_param) = display_param_builder.build()?.take() {
|
||||
gpu_params.displays.push(display_param);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gfxstream")]
|
||||
{
|
||||
if !vulkan_specified && gpu_params.mode == GpuMode::ModeGfxstream {
|
||||
gpu_params.use_vulkan = sys::use_vulkan();
|
||||
}
|
||||
|
||||
if syncfd_specified || angle_specified {
|
||||
match gpu_params.mode {
|
||||
GpuMode::ModeGfxstream => {}
|
||||
_ => {
|
||||
return Err(
|
||||
"gpu parameter syncfd and angle are only supported for gfxstream backend"
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(gpu_params)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub fn parse_gpu_display_options(s: &str) -> Result<GpuDisplayParameters, String> {
|
||||
let mut display_param_builder: GpuDisplayParametersBuilder = Default::default();
|
||||
|
||||
for arg in s.split(',') {
|
||||
display_param_builder
|
||||
.parse(arg)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
let display_param = display_param_builder.build()?;
|
||||
let display_param = display_param.ok_or_else(|| {
|
||||
invalid_value_err(s, "gpu-display must include both 'width' and 'height'")
|
||||
})?;
|
||||
|
||||
Ok(display_param)
|
||||
}
|
||||
|
||||
/// Aggregate of all configurable options for a running VM.
|
||||
#[remain::sorted]
|
||||
pub struct Config {
|
||||
|
@ -2276,20 +1932,6 @@ mod tests {
|
|||
.expect_err("parse should have failed");
|
||||
}
|
||||
|
||||
#[cfg(feature = "audio_cras")]
|
||||
#[test]
|
||||
fn parse_ac97_socket_type() {
|
||||
parse_ac97_options("socket_type=unified").expect("parse should have succeded");
|
||||
parse_ac97_options("socket_type=legacy").expect("parse should have succeded");
|
||||
}
|
||||
|
||||
#[cfg(feature = "audio")]
|
||||
#[test]
|
||||
fn parse_ac97_vios_valid() {
|
||||
parse_ac97_options("backend=vios,server=/path/to/server")
|
||||
.expect("parse should have succeded");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_serial_vaild() {
|
||||
parse_serial_options("type=syslog,num=1,console=true,stdin=true")
|
||||
|
@ -2362,30 +2004,6 @@ mod tests {
|
|||
.is_err())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_plugin_mount_valid() {
|
||||
let opt: BindMount = "/dev/null:/dev/zero:true".parse().unwrap();
|
||||
|
||||
assert_eq!(opt.src, PathBuf::from("/dev/null"));
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/zero"));
|
||||
assert!(opt.writable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_plugin_mount_valid_shorthand() {
|
||||
let opt: BindMount = "/dev/null".parse().unwrap();
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/null"));
|
||||
assert!(!opt.writable);
|
||||
|
||||
let opt: BindMount = "/dev/null:/dev/zero".parse().unwrap();
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/zero"));
|
||||
assert!(!opt.writable);
|
||||
|
||||
let opt: BindMount = "/dev/null::true".parse().unwrap();
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/null"));
|
||||
assert!(opt.writable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_plugin_mount_invalid() {
|
||||
"".parse::<BindMount>().expect_err("parse should fail");
|
||||
|
@ -2404,6 +2022,7 @@ mod tests {
|
|||
.expect_err("parse should fail because flag is not boolean");
|
||||
}
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
#[test]
|
||||
fn parse_plugin_gid_map_valid() {
|
||||
let opt: GidMap = "1:2:3".parse().expect("parse should succeed");
|
||||
|
@ -2412,6 +2031,7 @@ mod tests {
|
|||
assert_eq!(opt.count, 3);
|
||||
}
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
#[test]
|
||||
fn parse_plugin_gid_map_valid_shorthand() {
|
||||
let opt: GidMap = "1".parse().expect("parse should succeed");
|
||||
|
@ -2430,6 +2050,7 @@ mod tests {
|
|||
assert_eq!(opt.count, 3);
|
||||
}
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
#[test]
|
||||
fn parse_plugin_gid_map_invalid() {
|
||||
"".parse::<GidMap>().expect_err("parse should fail");
|
||||
|
@ -2447,243 +2068,6 @@ mod tests {
|
|||
.expect_err("parse should fail because count is not a number");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_touch_spec_and_track_pad_spec_default_size() {
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
"/dev/single-touch-test",
|
||||
"--trackpad",
|
||||
"/dev/single-touch-test",
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(DEFAULT_TOUCH_DEVICE_WIDTH, DEFAULT_TOUCH_DEVICE_HEIGHT)
|
||||
);
|
||||
assert_eq!(
|
||||
config.virtio_trackpad.first().unwrap().get_size(),
|
||||
(DEFAULT_TOUCH_DEVICE_WIDTH, DEFAULT_TOUCH_DEVICE_HEIGHT)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn single_touch_spec_default_size_from_gpu() {
|
||||
let width = 12345u32;
|
||||
let height = 54321u32;
|
||||
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
"/dev/single-touch-test",
|
||||
"--gpu",
|
||||
&format!("width={},height={}", width, height),
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(width, height)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_touch_spec_and_track_pad_spec_with_size() {
|
||||
let width = 12345u32;
|
||||
let height = 54321u32;
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
&format!("/dev/single-touch-test:{}:{}", width, height),
|
||||
"--trackpad",
|
||||
&format!("/dev/single-touch-test:{}:{}", width, height),
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(width, height)
|
||||
);
|
||||
assert_eq!(
|
||||
config.virtio_trackpad.first().unwrap().get_size(),
|
||||
(width, height)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn single_touch_spec_with_size_independent_from_gpu() {
|
||||
let touch_width = 12345u32;
|
||||
let touch_height = 54321u32;
|
||||
let display_width = 1234u32;
|
||||
let display_height = 5432u32;
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
&format!("/dev/single-touch-test:{}:{}", touch_width, touch_height),
|
||||
"--gpu",
|
||||
&format!("width={},height={}", display_width, display_height),
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(touch_width, touch_height)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn virtio_switches() {
|
||||
let mut config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&["--switches", "/dev/switches-test", "/dev/null"],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_switches.pop().unwrap(),
|
||||
PathBuf::from("/dev/switches-test")
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_default_vulkan_support() {
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("backend=virglrenderer").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gfxstream")]
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("backend=gfxstream").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_with_vulkan_specified() {
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("vulkan=true").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=virglrenderer,vulkan=true").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("vulkan=true,backend=virglrenderer").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("vulkan=false").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=virglrenderer,vulkan=false").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("vulkan=false,backend=virglrenderer").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("backend=virglrenderer,vulkan=invalid_value").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("vulkan=invalid_value,backend=virglrenderer").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "gpu", feature = "gfxstream"))]
|
||||
#[test]
|
||||
fn parse_gpu_options_gfxstream_with_syncfd_specified() {
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=gfxstream,syncfd=true").unwrap();
|
||||
|
||||
assert!(gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("syncfd=true,backend=gfxstream").unwrap();
|
||||
assert!(gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=gfxstream,syncfd=false").unwrap();
|
||||
|
||||
assert!(!gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("syncfd=false,backend=gfxstream").unwrap();
|
||||
assert!(!gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("backend=gfxstream,syncfd=invalid_value").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("syncfd=invalid_value,backend=gfxstream").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "gpu", feature = "gfxstream"))]
|
||||
#[test]
|
||||
fn parse_gpu_options_not_gfxstream_with_syncfd_specified() {
|
||||
{
|
||||
assert!(parse_gpu_options("backend=virglrenderer,syncfd=true").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("syncfd=true,backend=virglrenderer").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_gfxstream_with_wsi_specified() {
|
||||
use rutabaga_gfx::RutabagaWsi;
|
||||
|
||||
let gpu_params: GpuParameters = parse_gpu_options("backend=virglrenderer,wsi=vk").unwrap();
|
||||
assert!(matches!(gpu_params.wsi, Some(RutabagaWsi::Vulkan)));
|
||||
|
||||
let gpu_params: GpuParameters = parse_gpu_options("wsi=vk,backend=virglrenderer").unwrap();
|
||||
assert!(matches!(gpu_params.wsi, Some(RutabagaWsi::Vulkan)));
|
||||
|
||||
assert!(parse_gpu_options("backend=virglrenderer,wsi=invalid_value").is_err());
|
||||
|
||||
assert!(parse_gpu_options("wsi=invalid_value,backend=virglrenderer").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_battery_vaild() {
|
||||
parse_battery_options("type=goldfish").expect("parse should have succeded");
|
||||
|
@ -2846,81 +2230,4 @@ mod tests {
|
|||
assert!(parse_userspace_msr_options("0x10").is_err());
|
||||
assert!(parse_userspace_msr_options("hoge").is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_display_options_valid() {
|
||||
{
|
||||
let gpu_params: GpuDisplayParameters =
|
||||
parse_gpu_display_options("width=500,height=600").unwrap();
|
||||
assert_eq!(gpu_params.width, 500);
|
||||
assert_eq!(gpu_params.height, 600);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_display_options_invalid() {
|
||||
{
|
||||
assert!(parse_gpu_display_options("width=500").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_display_options("height=500").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_display_options("width").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_display_options("blah").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_and_gpu_display_options_valid() {
|
||||
{
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--gpu",
|
||||
"2D,width=500,height=600",
|
||||
"--gpu-display",
|
||||
"width=700,height=800",
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let gpu_params = config.gpu_parameters.unwrap();
|
||||
|
||||
assert_eq!(gpu_params.displays.len(), 2);
|
||||
assert_eq!(gpu_params.displays[0].width, 500);
|
||||
assert_eq!(gpu_params.displays[0].height, 600);
|
||||
assert_eq!(gpu_params.displays[1].width, 700);
|
||||
assert_eq!(gpu_params.displays[1].height, 800);
|
||||
}
|
||||
{
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--gpu",
|
||||
"2D",
|
||||
"--gpu-display",
|
||||
"width=700,height=800",
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let gpu_params = config.gpu_parameters.unwrap();
|
||||
|
||||
assert_eq!(gpu_params.displays.len(), 1);
|
||||
assert_eq!(gpu_params.displays[0].width, 700);
|
||||
assert_eq!(gpu_params.displays[0].height, 800);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@ use std::time::Duration;
|
|||
|
||||
use devices::SerialParameters;
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
use devices::virtio::{GpuDisplayParameters, GpuParameters};
|
||||
|
||||
use crate::crosvm::config::Config;
|
||||
#[cfg(feature = "gpu")]
|
||||
use crate::crosvm::{argument, argument::parse_hex_or_decimal, config::invalid_value_err};
|
||||
|
||||
#[cfg(all(feature = "gpu", feature = "virgl_renderer_next"))]
|
||||
pub fn parse_gpu_render_server_options(
|
||||
|
@ -182,3 +187,712 @@ pub fn validate_config(cfg: &mut Config) -> std::result::Result<(), String> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[derive(Default)]
|
||||
struct GpuDisplayParametersBuilder {
|
||||
width: Option<u32>,
|
||||
height: Option<u32>,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
impl GpuDisplayParametersBuilder {
|
||||
fn parse(&mut self, arg: &str) -> argument::Result<()> {
|
||||
let mut kv = arg.split('=');
|
||||
let k = kv.next().unwrap_or("");
|
||||
let v = kv.next().unwrap_or("");
|
||||
match k {
|
||||
"width" => {
|
||||
let width = v
|
||||
.parse::<u32>()
|
||||
.map_err(|_| argument::Error::InvalidValue {
|
||||
value: v.to_string(),
|
||||
expected: String::from("gpu parameter 'width' must be a valid integer"),
|
||||
})?;
|
||||
self.width = Some(width);
|
||||
}
|
||||
"height" => {
|
||||
let height = v
|
||||
.parse::<u32>()
|
||||
.map_err(|_| argument::Error::InvalidValue {
|
||||
value: v.to_string(),
|
||||
expected: String::from("gpu parameter 'height' must be a valid integer"),
|
||||
})?;
|
||||
self.height = Some(height);
|
||||
}
|
||||
_ => {
|
||||
return Err(argument::Error::UnknownArgument(format!(
|
||||
"gpu-display parameter {}",
|
||||
k
|
||||
)))
|
||||
}
|
||||
}
|
||||
self.args.push(arg.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build(&self) -> Result<Option<GpuDisplayParameters>, String> {
|
||||
match (self.width, self.height) {
|
||||
(None, None) => Ok(None),
|
||||
(None, Some(_)) | (Some(_), None) => {
|
||||
let mut value = self
|
||||
.args
|
||||
.clone()
|
||||
.into_iter()
|
||||
.fold(String::new(), |args_so_far, arg| args_so_far + &arg + ",");
|
||||
value.pop();
|
||||
return Err(invalid_value_err(
|
||||
value,
|
||||
"gpu must include both 'width' and 'height' if either is supplied",
|
||||
));
|
||||
}
|
||||
(Some(width), Some(height)) => Ok(Some(GpuDisplayParameters { width, height })),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub fn parse_gpu_options(s: &str) -> Result<GpuParameters, String> {
|
||||
use devices::virtio::GpuMode;
|
||||
use rutabaga_gfx::RutabagaWsi;
|
||||
|
||||
use crate::crosvm::sys::config::is_gpu_backend_deprecated;
|
||||
|
||||
#[cfg(feature = "gfxstream")]
|
||||
let mut vulkan_specified = false;
|
||||
#[cfg(feature = "gfxstream")]
|
||||
let mut syncfd_specified = false;
|
||||
#[cfg(feature = "gfxstream")]
|
||||
let mut angle_specified = false;
|
||||
|
||||
let mut display_param_builder: GpuDisplayParametersBuilder = Default::default();
|
||||
let mut gpu_params = GpuParameters::default();
|
||||
|
||||
for frag in s.split(',') {
|
||||
let mut rest: Option<&str> = None;
|
||||
let mut kv = frag.split('=');
|
||||
let k = kv.next().unwrap_or("");
|
||||
let v = kv.next().unwrap_or("");
|
||||
match k {
|
||||
// Deprecated: Specifying --gpu=<mode> Not great as the mode can be set multiple
|
||||
// times if the user specifies several modes (--gpu=2d,virglrenderer,gfxstream)
|
||||
"2d" | "2D" => {
|
||||
gpu_params.mode = GpuMode::Mode2D;
|
||||
}
|
||||
"3d" | "3D" | "virglrenderer" => {
|
||||
gpu_params.mode = GpuMode::ModeVirglRenderer;
|
||||
}
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"gfxstream" => {
|
||||
gpu_params.mode = GpuMode::ModeGfxstream;
|
||||
}
|
||||
// Preferred: Specifying --gpu,backend=<mode>
|
||||
"backend" => match v {
|
||||
"2d" | "2D" => {
|
||||
if is_gpu_backend_deprecated(v) {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"this backend type is deprecated, please use gfxstream.",
|
||||
));
|
||||
} else {
|
||||
gpu_params.mode = GpuMode::Mode2D;
|
||||
}
|
||||
}
|
||||
"3d" | "3D" | "virglrenderer" => {
|
||||
if is_gpu_backend_deprecated(v) {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"this backend type is deprecated, please use gfxstream.",
|
||||
));
|
||||
} else {
|
||||
gpu_params.mode = GpuMode::ModeVirglRenderer;
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"gfxstream" => {
|
||||
gpu_params.mode = GpuMode::ModeGfxstream;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"gpu parameter 'backend' should be one of (2d|virglrenderer|gfxstream)",
|
||||
#[cfg(not(feature = "gfxstream"))]
|
||||
"gpu parameter 'backend' should be one of (2d|3d)",
|
||||
));
|
||||
}
|
||||
},
|
||||
"egl" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_egl = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_egl = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'egl' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"gles" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_gles = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_gles = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'gles' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"glx" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_glx = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_glx = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'glx' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"surfaceless" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.renderer_use_surfaceless = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.renderer_use_surfaceless = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'surfaceless' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"syncfd" => {
|
||||
syncfd_specified = true;
|
||||
match v {
|
||||
"true" | "" => {
|
||||
gpu_params.gfxstream_use_syncfd = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.gfxstream_use_syncfd = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(argument::Error::InvalidValue {
|
||||
value: v.to_string(),
|
||||
expected: String::from("gpu parameter 'syncfd' should be a boolean"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "gfxstream")]
|
||||
"angle" => {
|
||||
angle_specified = true;
|
||||
match v {
|
||||
"true" | "" => {
|
||||
gpu_params.gfxstream_use_guest_angle = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.gfxstream_use_guest_angle = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'angle' should be a boolean",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
"vulkan" => {
|
||||
#[cfg(feature = "gfxstream")]
|
||||
{
|
||||
vulkan_specified = true;
|
||||
}
|
||||
match v {
|
||||
"true" | "" => {
|
||||
gpu_params.use_vulkan = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.use_vulkan = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'vulkan' should be a boolean",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
"wsi" => match v {
|
||||
"vk" => {
|
||||
gpu_params.wsi = Some(RutabagaWsi::Vulkan);
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(v, "gpu parameter 'wsi' should be vk"));
|
||||
}
|
||||
},
|
||||
"cache-path" => gpu_params.cache_path = Some(v.to_string()),
|
||||
"cache-size" => gpu_params.cache_size = Some(v.to_string()),
|
||||
"pci-bar-size" => {
|
||||
let size = parse_hex_or_decimal(v).map_err(|_| {
|
||||
"gpu parameter `pci-bar-size` must be a valid hex or decimal value"
|
||||
})?;
|
||||
gpu_params.pci_bar_size = size;
|
||||
}
|
||||
"udmabuf" => match v {
|
||||
"true" | "" => {
|
||||
gpu_params.udmabuf = true;
|
||||
}
|
||||
"false" => {
|
||||
gpu_params.udmabuf = false;
|
||||
}
|
||||
_ => {
|
||||
return Err(invalid_value_err(
|
||||
v,
|
||||
"gpu parameter 'udmabuf' should be a boolean",
|
||||
));
|
||||
}
|
||||
},
|
||||
"context-types" => {
|
||||
let context_types: Vec<String> = v.split(':').map(|s| s.to_string()).collect();
|
||||
gpu_params.context_mask = rutabaga_gfx::calculate_context_mask(context_types);
|
||||
}
|
||||
"" => {}
|
||||
_ => {
|
||||
rest = Some(frag);
|
||||
}
|
||||
}
|
||||
if let Some(arg) = rest.take() {
|
||||
match display_param_builder.parse(arg) {
|
||||
Ok(()) => {}
|
||||
Err(argument::Error::UnknownArgument(_)) => {
|
||||
rest = Some(arg);
|
||||
}
|
||||
Err(err) => return Err(err.to_string()),
|
||||
}
|
||||
}
|
||||
if let Some(arg) = rest.take() {
|
||||
return Err(format!("unknown gpu parameter {}", arg));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(display_param) = display_param_builder.build()?.take() {
|
||||
gpu_params.displays.push(display_param);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gfxstream")]
|
||||
{
|
||||
if !vulkan_specified && gpu_params.mode == GpuMode::ModeGfxstream {
|
||||
gpu_params.use_vulkan = sys::use_vulkan();
|
||||
}
|
||||
|
||||
if syncfd_specified || angle_specified {
|
||||
match gpu_params.mode {
|
||||
GpuMode::ModeGfxstream => {}
|
||||
_ => {
|
||||
return Err(
|
||||
"gpu parameter syncfd and angle are only supported for gfxstream backend"
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(gpu_params)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub fn parse_gpu_display_options(s: &str) -> Result<GpuDisplayParameters, String> {
|
||||
let mut display_param_builder: GpuDisplayParametersBuilder = Default::default();
|
||||
|
||||
for arg in s.split(',') {
|
||||
display_param_builder
|
||||
.parse(arg)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
let display_param = display_param_builder.build()?;
|
||||
let display_param = display_param.ok_or_else(|| {
|
||||
invalid_value_err(s, "gpu-display must include both 'width' and 'height'")
|
||||
})?;
|
||||
|
||||
Ok(display_param)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::crosvm::config::{DEFAULT_TOUCH_DEVICE_HEIGHT, DEFAULT_TOUCH_DEVICE_WIDTH};
|
||||
|
||||
use argh::FromArgs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(feature = "audio")]
|
||||
use crate::crosvm::config::parse_ac97_options;
|
||||
use crate::crosvm::config::BindMount;
|
||||
|
||||
#[cfg(feature = "audio_cras")]
|
||||
#[test]
|
||||
fn parse_ac97_socket_type() {
|
||||
parse_ac97_options("socket_type=unified").expect("parse should have succeded");
|
||||
parse_ac97_options("socket_type=legacy").expect("parse should have succeded");
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_default_vulkan_support() {
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("backend=virglrenderer").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gfxstream")]
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("backend=gfxstream").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_with_vulkan_specified() {
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("vulkan=true").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=virglrenderer,vulkan=true").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("vulkan=true,backend=virglrenderer").unwrap();
|
||||
assert!(gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters = parse_gpu_options("vulkan=false").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=virglrenderer,vulkan=false").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("vulkan=false,backend=virglrenderer").unwrap();
|
||||
assert!(!gpu_params.use_vulkan);
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("backend=virglrenderer,vulkan=invalid_value").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("vulkan=invalid_value,backend=virglrenderer").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "gpu", feature = "gfxstream"))]
|
||||
#[test]
|
||||
fn parse_gpu_options_gfxstream_with_syncfd_specified() {
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=gfxstream,syncfd=true").unwrap();
|
||||
|
||||
assert!(gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("syncfd=true,backend=gfxstream").unwrap();
|
||||
assert!(gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("backend=gfxstream,syncfd=false").unwrap();
|
||||
|
||||
assert!(!gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
let gpu_params: GpuParameters =
|
||||
parse_gpu_options("syncfd=false,backend=gfxstream").unwrap();
|
||||
assert!(!gpu_params.gfxstream_use_syncfd);
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("backend=gfxstream,syncfd=invalid_value").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("syncfd=invalid_value,backend=gfxstream").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "gpu", feature = "gfxstream"))]
|
||||
#[test]
|
||||
fn parse_gpu_options_not_gfxstream_with_syncfd_specified() {
|
||||
{
|
||||
assert!(parse_gpu_options("backend=virglrenderer,syncfd=true").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_options("syncfd=true,backend=virglrenderer").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_gfxstream_with_wsi_specified() {
|
||||
use rutabaga_gfx::RutabagaWsi;
|
||||
|
||||
let gpu_params: GpuParameters = parse_gpu_options("backend=virglrenderer,wsi=vk").unwrap();
|
||||
assert!(matches!(gpu_params.wsi, Some(RutabagaWsi::Vulkan)));
|
||||
|
||||
let gpu_params: GpuParameters = parse_gpu_options("wsi=vk,backend=virglrenderer").unwrap();
|
||||
assert!(matches!(gpu_params.wsi, Some(RutabagaWsi::Vulkan)));
|
||||
|
||||
assert!(parse_gpu_options("backend=virglrenderer,wsi=invalid_value").is_err());
|
||||
|
||||
assert!(parse_gpu_options("wsi=invalid_value,backend=virglrenderer").is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_display_options_valid() {
|
||||
{
|
||||
let gpu_params: GpuDisplayParameters =
|
||||
parse_gpu_display_options("width=500,height=600").unwrap();
|
||||
assert_eq!(gpu_params.width, 500);
|
||||
assert_eq!(gpu_params.height, 600);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_display_options_invalid() {
|
||||
{
|
||||
assert!(parse_gpu_display_options("width=500").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_display_options("height=500").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_display_options("width").is_err());
|
||||
}
|
||||
{
|
||||
assert!(parse_gpu_display_options("blah").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn parse_gpu_options_and_gpu_display_options_valid() {
|
||||
{
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--gpu",
|
||||
"2D,width=500,height=600",
|
||||
"--gpu-display",
|
||||
"width=700,height=800",
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let gpu_params = config.gpu_parameters.unwrap();
|
||||
|
||||
assert_eq!(gpu_params.displays.len(), 2);
|
||||
assert_eq!(gpu_params.displays[0].width, 500);
|
||||
assert_eq!(gpu_params.displays[0].height, 600);
|
||||
assert_eq!(gpu_params.displays[1].width, 700);
|
||||
assert_eq!(gpu_params.displays[1].height, 800);
|
||||
}
|
||||
{
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--gpu",
|
||||
"2D",
|
||||
"--gpu-display",
|
||||
"width=700,height=800",
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let gpu_params = config.gpu_parameters.unwrap();
|
||||
|
||||
assert_eq!(gpu_params.displays.len(), 1);
|
||||
assert_eq!(gpu_params.displays[0].width, 700);
|
||||
assert_eq!(gpu_params.displays[0].height, 800);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "audio")]
|
||||
#[test]
|
||||
fn parse_ac97_vios_valid() {
|
||||
parse_ac97_options("backend=vios,server=/path/to/server")
|
||||
.expect("parse should have succeded");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_plugin_mount_valid() {
|
||||
let opt: BindMount = "/dev/null:/dev/zero:true".parse().unwrap();
|
||||
|
||||
assert_eq!(opt.src, PathBuf::from("/dev/null"));
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/zero"));
|
||||
assert!(opt.writable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_plugin_mount_valid_shorthand() {
|
||||
let opt: BindMount = "/dev/null".parse().unwrap();
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/null"));
|
||||
assert!(!opt.writable);
|
||||
|
||||
let opt: BindMount = "/dev/null:/dev/zero".parse().unwrap();
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/zero"));
|
||||
assert!(!opt.writable);
|
||||
|
||||
let opt: BindMount = "/dev/null::true".parse().unwrap();
|
||||
assert_eq!(opt.dst, PathBuf::from("/dev/null"));
|
||||
assert!(opt.writable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_touch_spec_and_track_pad_spec_default_size() {
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
"/dev/single-touch-test",
|
||||
"--trackpad",
|
||||
"/dev/single-touch-test",
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(DEFAULT_TOUCH_DEVICE_WIDTH, DEFAULT_TOUCH_DEVICE_HEIGHT)
|
||||
);
|
||||
assert_eq!(
|
||||
config.virtio_trackpad.first().unwrap().get_size(),
|
||||
(DEFAULT_TOUCH_DEVICE_WIDTH, DEFAULT_TOUCH_DEVICE_HEIGHT)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn single_touch_spec_default_size_from_gpu() {
|
||||
let width = 12345u32;
|
||||
let height = 54321u32;
|
||||
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
"/dev/single-touch-test",
|
||||
"--gpu",
|
||||
&format!("width={},height={}", width, height),
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(width, height)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_touch_spec_and_track_pad_spec_with_size() {
|
||||
let width = 12345u32;
|
||||
let height = 54321u32;
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
&format!("/dev/single-touch-test:{}:{}", width, height),
|
||||
"--trackpad",
|
||||
&format!("/dev/single-touch-test:{}:{}", width, height),
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(width, height)
|
||||
);
|
||||
assert_eq!(
|
||||
config.virtio_trackpad.first().unwrap().get_size(),
|
||||
(width, height)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
#[test]
|
||||
fn single_touch_spec_with_size_independent_from_gpu() {
|
||||
let touch_width = 12345u32;
|
||||
let touch_height = 54321u32;
|
||||
let display_width = 1234u32;
|
||||
let display_height = 5432u32;
|
||||
let config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&[
|
||||
"--single-touch",
|
||||
&format!("/dev/single-touch-test:{}:{}", touch_width, touch_height),
|
||||
"--gpu",
|
||||
&format!("width={},height={}", display_width, display_height),
|
||||
"/dev/null",
|
||||
],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_single_touch.first().unwrap().get_size(),
|
||||
(touch_width, touch_height)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn virtio_switches() {
|
||||
let mut config: Config = crate::crosvm::cmdline::RunCommand::from_args(
|
||||
&[],
|
||||
&["--switches", "/dev/switches-test", "/dev/null"],
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.virtio_switches.pop().unwrap(),
|
||||
PathBuf::from("/dev/switches-test")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue