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