vm_control/
gpu.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
5use std::collections::BTreeMap as Map;
6use std::fmt;
7use std::fmt::Display;
8use std::path::Path;
9
10use serde::Deserialize;
11use serde::Serialize;
12use serde_keyvalue::FromKeyValues;
13
14pub use crate::sys::handle_request;
15pub use crate::sys::DisplayMode;
16pub use crate::sys::MouseMode;
17pub use crate::*;
18
19pub const DEFAULT_DISPLAY_WIDTH: u32 = 1280;
20pub const DEFAULT_DISPLAY_HEIGHT: u32 = 1024;
21pub const DEFAULT_DPI: u32 = 320;
22pub const DEFAULT_REFRESH_RATE: u32 = 60;
23
24fn default_refresh_rate() -> u32 {
25    DEFAULT_REFRESH_RATE
26}
27
28fn default_dpi() -> (u32, u32) {
29    (DEFAULT_DPI, DEFAULT_DPI)
30}
31
32/// Trait that the platform-specific type `DisplayMode` needs to implement.
33pub(crate) trait DisplayModeTrait {
34    /// Returns the initial host window size.
35    fn get_window_size(&self) -> (u32, u32);
36
37    /// Returns the virtual display size used for creating the display device.
38    ///
39    /// We need to query the phenotype flags to see if resolutions higher than 1080p should be
40    /// enabled. This functions assumes process invariants have been set up and phenotype flags are
41    /// available. If not, use `get_virtual_display_size_4k_uhd()` instead.
42    ///
43    /// This may be different from the initial host window size since different display backends may
44    /// have different alignment requirements on it.
45    fn get_virtual_display_size(&self) -> (u32, u32);
46
47    /// Returns the virtual display size used for creating the display device.
48    ///
49    /// While `get_virtual_display_size()` reads phenotype flags internally, this function does not,
50    /// so it can be used when process invariants and phenotype flags are not yet ready.
51    fn get_virtual_display_size_4k_uhd(&self, is_4k_uhd_enabled: bool) -> (u32, u32);
52}
53
54impl Default for DisplayMode {
55    fn default() -> Self {
56        Self::Windowed(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
57    }
58}
59
60#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
61#[serde(deny_unknown_fields, rename_all = "kebab-case")]
62pub struct DisplayParameters {
63    #[serde(default)]
64    pub mode: DisplayMode,
65    #[serde(default)]
66    pub hidden: bool,
67    #[serde(default = "default_refresh_rate")]
68    pub refresh_rate: u32,
69    #[serde(default = "default_dpi")]
70    pub dpi: (u32, u32),
71}
72
73impl DisplayParameters {
74    pub fn new(
75        mode: DisplayMode,
76        hidden: bool,
77        refresh_rate: u32,
78        horizontal_dpi: u32,
79        vertical_dpi: u32,
80    ) -> Self {
81        Self {
82            mode,
83            hidden,
84            refresh_rate,
85            dpi: (horizontal_dpi, vertical_dpi),
86        }
87    }
88
89    pub fn default_with_mode(mode: DisplayMode) -> Self {
90        Self::new(mode, false, DEFAULT_REFRESH_RATE, DEFAULT_DPI, DEFAULT_DPI)
91    }
92
93    pub fn get_window_size(&self) -> (u32, u32) {
94        self.mode.get_window_size()
95    }
96
97    pub fn get_virtual_display_size(&self) -> (u32, u32) {
98        self.mode.get_virtual_display_size()
99    }
100
101    pub fn get_virtual_display_size_4k_uhd(&self, is_4k_uhd_enabled: bool) -> (u32, u32) {
102        self.mode.get_virtual_display_size_4k_uhd(is_4k_uhd_enabled)
103    }
104
105    pub fn horizontal_dpi(&self) -> u32 {
106        self.dpi.0
107    }
108
109    pub fn vertical_dpi(&self) -> u32 {
110        self.dpi.1
111    }
112}
113
114impl Default for DisplayParameters {
115    fn default() -> Self {
116        Self::default_with_mode(Default::default())
117    }
118}
119
120#[derive(Serialize, Deserialize, Debug)]
121pub enum GpuControlCommand {
122    AddDisplays {
123        displays: Vec<DisplayParameters>,
124    },
125    ListDisplays,
126    RemoveDisplays {
127        display_ids: Vec<u32>,
128    },
129    SetDisplayMouseMode {
130        display_id: u32,
131        mouse_mode: MouseMode,
132    },
133}
134
135#[derive(Serialize, Deserialize, Debug, Clone)]
136pub enum GpuControlResult {
137    DisplaysUpdated,
138    DisplayList {
139        displays: Map<u32, DisplayParameters>,
140    },
141    TooManyDisplays {
142        allowed: usize,
143        requested: usize,
144    },
145    NoSuchDisplay {
146        display_id: u32,
147    },
148    DisplayMouseModeSet,
149    ErrString(String),
150}
151
152impl Display for GpuControlResult {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        use self::GpuControlResult::*;
155
156        match self {
157            DisplaysUpdated => write!(f, "displays updated"),
158            DisplayList { displays } => {
159                let json: serde_json::Value = serde_json::json!({
160                    "displays": displays,
161                });
162                let json_pretty =
163                    serde_json::to_string_pretty(&json).map_err(|_| std::fmt::Error)?;
164                write!(f, "{json_pretty}")
165            }
166            TooManyDisplays { allowed, requested } => write!(
167                f,
168                "too_many_displays: allowed {allowed}, requested {requested}"
169            ),
170            NoSuchDisplay { display_id } => write!(f, "no_such_display {display_id}"),
171            DisplayMouseModeSet => write!(f, "display_mouse_mode_set"),
172            ErrString(reason) => write!(f, "err_string {reason}"),
173        }
174    }
175}
176
177pub enum ModifyGpuError {
178    SocketFailed,
179    UnexpectedResponse(VmResponse),
180    UnknownCommand(String),
181    GpuControl(GpuControlResult),
182}
183
184impl fmt::Display for ModifyGpuError {
185    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186        use self::ModifyGpuError::*;
187
188        match self {
189            SocketFailed => write!(f, "socket failed"),
190            UnexpectedResponse(r) => write!(f, "unexpected response: {r}"),
191            UnknownCommand(c) => write!(f, "unknown display command: `{c}`"),
192            GpuControl(e) => write!(f, "{e}"),
193        }
194    }
195}
196
197pub type ModifyGpuResult = std::result::Result<GpuControlResult, ModifyGpuError>;
198
199impl From<VmResponse> for ModifyGpuResult {
200    fn from(response: VmResponse) -> Self {
201        match response {
202            VmResponse::GpuResponse(gpu_response) => Ok(gpu_response),
203            r => Err(ModifyGpuError::UnexpectedResponse(r)),
204        }
205    }
206}
207
208pub fn do_gpu_display_add<T: AsRef<Path> + std::fmt::Debug>(
209    control_socket_path: T,
210    displays: Vec<DisplayParameters>,
211) -> ModifyGpuResult {
212    let request = VmRequest::GpuCommand(GpuControlCommand::AddDisplays { displays });
213    handle_request(&request, control_socket_path)
214        .map_err(|_| ModifyGpuError::SocketFailed)?
215        .into()
216}
217
218pub fn do_gpu_display_list<T: AsRef<Path> + std::fmt::Debug>(
219    control_socket_path: T,
220) -> ModifyGpuResult {
221    let request = VmRequest::GpuCommand(GpuControlCommand::ListDisplays);
222    handle_request(&request, control_socket_path)
223        .map_err(|_| ModifyGpuError::SocketFailed)?
224        .into()
225}
226
227pub fn do_gpu_display_remove<T: AsRef<Path> + std::fmt::Debug>(
228    control_socket_path: T,
229    display_ids: Vec<u32>,
230) -> ModifyGpuResult {
231    let request = VmRequest::GpuCommand(GpuControlCommand::RemoveDisplays { display_ids });
232    handle_request(&request, control_socket_path)
233        .map_err(|_| ModifyGpuError::SocketFailed)?
234        .into()
235}
236
237pub fn do_gpu_set_display_mouse_mode<T: AsRef<Path> + std::fmt::Debug>(
238    control_socket_path: T,
239    display_id: u32,
240    mouse_mode: MouseMode,
241) -> ModifyGpuResult {
242    let request = VmRequest::GpuCommand(GpuControlCommand::SetDisplayMouseMode {
243        display_id,
244        mouse_mode,
245    });
246    handle_request(&request, control_socket_path)
247        .map_err(|_| ModifyGpuError::SocketFailed)?
248        .into()
249}