devices/virtio/gpu/
parameters.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Definitions and utilities for GPU related parameters.
6
7#[cfg(windows)]
8use std::marker::PhantomData;
9use std::path::PathBuf;
10
11use serde::Deserialize;
12use serde::Deserializer;
13use serde::Serialize;
14use serde::Serializer;
15use serde_keyvalue::FromKeyValues;
16use vm_control::gpu::DisplayParameters;
17
18use super::GpuMode;
19use super::GpuWsi;
20use crate::virtio::gpu::VIRTIO_GPU_MAX_SCANOUTS;
21use crate::PciAddress;
22
23mod serde_capset_mask {
24    use super::*;
25
26    pub fn serialize<S>(capset_mask: &u64, serializer: S) -> Result<S::Ok, S::Error>
27    where
28        S: Serializer,
29    {
30        let context_types = rutabaga_gfx::calculate_capset_names(*capset_mask).join(":");
31
32        serializer.serialize_str(context_types.as_str())
33    }
34
35    pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u64, D::Error> {
36        let s = String::deserialize(deserializer)?;
37        Ok(rutabaga_gfx::calculate_capset_mask(s.split(':')))
38    }
39}
40
41#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
42pub enum AudioDeviceMode {
43    #[serde(rename = "per-surface")]
44    PerSurface,
45    #[serde(rename = "one-global")]
46    OneGlobal,
47}
48
49#[derive(Clone, Debug, Serialize, Deserialize, FromKeyValues)]
50#[serde(deny_unknown_fields, default, rename_all = "kebab-case")]
51pub struct GpuParameters {
52    #[serde(rename = "backend")]
53    pub mode: GpuMode,
54    #[serde(default = "default_max_num_displays")]
55    pub max_num_displays: u32,
56    #[serde(default = "default_audio_device_mode")]
57    pub audio_device_mode: AudioDeviceMode,
58    #[serde(rename = "displays")]
59    pub display_params: Vec<DisplayParameters>,
60    // `width` and `height` are supported for CLI backwards compatibility.
61    #[serde(rename = "width")]
62    pub __width_compat: Option<u32>,
63    #[serde(rename = "height")]
64    pub __height_compat: Option<u32>,
65    #[serde(rename = "egl")]
66    pub renderer_use_egl: bool,
67    #[serde(rename = "gles")]
68    pub renderer_use_gles: bool,
69    #[serde(rename = "glx")]
70    pub renderer_use_glx: bool,
71    #[serde(rename = "surfaceless")]
72    pub renderer_use_surfaceless: bool,
73    #[serde(rename = "vulkan")]
74    pub use_vulkan: Option<bool>,
75    pub wsi: Option<GpuWsi>,
76    pub udmabuf: bool,
77    pub cache_path: Option<String>,
78    pub cache_size: Option<String>,
79    pub pci_address: Option<PciAddress>,
80    pub pci_bar_size: u64,
81    #[serde(rename = "context-types", with = "serde_capset_mask")]
82    pub capset_mask: u64,
83    // enforce that blob resources MUST be exportable as file descriptors
84    pub external_blob: bool,
85    pub system_blob: bool,
86    // enable use of descriptor mapping to fixed host VA within a prepared vMMU mapping (e.g. kvm
87    // user memslot)
88    pub fixed_blob_mapping: bool,
89    #[serde(rename = "implicit-render-server")]
90    pub allow_implicit_render_server_exec: bool,
91    // Passthrough parameters sent to the underlying renderer in a renderer-specific format.
92    pub renderer_features: Option<String>,
93    // When running with device sandboxing, the path of a directory available for
94    // scratch space.
95    pub snapshot_scratch_path: Option<PathBuf>,
96}
97
98impl Default for GpuParameters {
99    fn default() -> Self {
100        GpuParameters {
101            max_num_displays: default_max_num_displays(),
102            audio_device_mode: default_audio_device_mode(),
103            display_params: vec![],
104            __width_compat: None,
105            __height_compat: None,
106            renderer_use_egl: true,
107            renderer_use_gles: true,
108            renderer_use_glx: false,
109            renderer_use_surfaceless: true,
110            use_vulkan: None,
111            mode: Default::default(),
112            wsi: None,
113            cache_path: None,
114            cache_size: None,
115            pci_address: None,
116            pci_bar_size: (1 << 33),
117            udmabuf: false,
118            capset_mask: 0,
119            external_blob: false,
120            system_blob: false,
121            fixed_blob_mapping: false,
122            allow_implicit_render_server_exec: false,
123            renderer_features: None,
124            snapshot_scratch_path: None,
125        }
126    }
127}
128
129fn default_max_num_displays() -> u32 {
130    VIRTIO_GPU_MAX_SCANOUTS as u32
131}
132
133fn default_audio_device_mode() -> AudioDeviceMode {
134    AudioDeviceMode::PerSurface
135}
136
137#[cfg(test)]
138mod tests {
139    use serde_json::*;
140
141    use super::*;
142
143    #[test]
144    fn capset_mask_serialize_deserialize() {
145        #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
146        struct CapsetMask {
147            #[serde(rename = "context-types", with = "serde_capset_mask")]
148            pub value: u64,
149        }
150
151        // Capset "virgl", id: 1, capset_mask: 0b0010
152        // Capset "gfxstream", id: 3, capset_mask: 0b1000
153        const CAPSET_MASK: u64 = 0b1010;
154        const SERIALIZED_CAPSET_MASK: &str = "{\"context-types\":\"virgl:gfxstream-vulkan\"}";
155
156        let capset_mask = CapsetMask { value: CAPSET_MASK };
157
158        assert_eq!(to_string(&capset_mask).unwrap(), SERIALIZED_CAPSET_MASK);
159        assert_eq!(
160            from_str::<CapsetMask>(SERIALIZED_CAPSET_MASK).unwrap(),
161            capset_mask
162        );
163    }
164}