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 {
146 allowed: usize,
147 requested: usize,
148 },
149 NoSuchDisplay {
150 display_id: u32,
151 },
152 DisplayMouseModeSet,
153 ErrString(String),
154 }
155
156 impl Display for GpuControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158 use self::GpuControlResult::*;
159
160 match self {
161 DisplaysUpdated => write!(f, "displays updated"),
162 DisplayList { displays } => {
163 let json: serde_json::Value = serde_json::json!({
164 "displays": displays,
165 });
166 let json_pretty =
167 serde_json::to_string_pretty(&json).map_err(|_| std::fmt::Error)?;
168 write!(f, "{}", json_pretty)
169 }
170 TooManyDisplays { allowed, requested } => write!(
171 f,
172 "too_many_displays: allowed {}, requested {}",
173 allowed, requested
174 ),
175 NoSuchDisplay { display_id } => write!(f, "no_such_display {}", display_id),
176 DisplayMouseModeSet => write!(f, "display_mouse_mode_set"),
177 ErrString(reason) => write!(f, "err_string {}", reason),
178 }
179 }
180 }
181
182 pub enum ModifyGpuError {
183 SocketFailed,
184 UnexpectedResponse(VmResponse),
185 UnknownCommand(String),
186 GpuControl(GpuControlResult),
187 }
188
189 impl fmt::Display for ModifyGpuError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result190 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191 use self::ModifyGpuError::*;
192
193 match self {
194 SocketFailed => write!(f, "socket failed"),
195 UnexpectedResponse(r) => write!(f, "unexpected response: {}", r),
196 UnknownCommand(c) => write!(f, "unknown display command: `{}`", c),
197 GpuControl(e) => write!(f, "{}", e),
198 }
199 }
200 }
201
202 pub type ModifyGpuResult = std::result::Result<GpuControlResult, ModifyGpuError>;
203
204 impl From<VmResponse> for ModifyGpuResult {
from(response: VmResponse) -> Self205 fn from(response: VmResponse) -> Self {
206 match response {
207 VmResponse::GpuResponse(gpu_response) => Ok(gpu_response),
208 r => Err(ModifyGpuError::UnexpectedResponse(r)),
209 }
210 }
211 }
212
do_gpu_display_add<T: AsRef<Path> + std::fmt::Debug>( control_socket_path: T, displays: Vec<DisplayParameters>, ) -> ModifyGpuResult213 pub fn do_gpu_display_add<T: AsRef<Path> + std::fmt::Debug>(
214 control_socket_path: T,
215 displays: Vec<DisplayParameters>,
216 ) -> ModifyGpuResult {
217 let request = VmRequest::GpuCommand(GpuControlCommand::AddDisplays { displays });
218 handle_request(&request, control_socket_path)
219 .map_err(|_| ModifyGpuError::SocketFailed)?
220 .into()
221 }
222
do_gpu_display_list<T: AsRef<Path> + std::fmt::Debug>( control_socket_path: T, ) -> ModifyGpuResult223 pub fn do_gpu_display_list<T: AsRef<Path> + std::fmt::Debug>(
224 control_socket_path: T,
225 ) -> ModifyGpuResult {
226 let request = VmRequest::GpuCommand(GpuControlCommand::ListDisplays);
227 handle_request(&request, control_socket_path)
228 .map_err(|_| ModifyGpuError::SocketFailed)?
229 .into()
230 }
231
do_gpu_display_remove<T: AsRef<Path> + std::fmt::Debug>( control_socket_path: T, display_ids: Vec<u32>, ) -> ModifyGpuResult232 pub fn do_gpu_display_remove<T: AsRef<Path> + std::fmt::Debug>(
233 control_socket_path: T,
234 display_ids: Vec<u32>,
235 ) -> ModifyGpuResult {
236 let request = VmRequest::GpuCommand(GpuControlCommand::RemoveDisplays { display_ids });
237 handle_request(&request, control_socket_path)
238 .map_err(|_| ModifyGpuError::SocketFailed)?
239 .into()
240 }
241
do_gpu_set_display_mouse_mode<T: AsRef<Path> + std::fmt::Debug>( control_socket_path: T, display_id: u32, mouse_mode: MouseMode, ) -> ModifyGpuResult242 pub fn do_gpu_set_display_mouse_mode<T: AsRef<Path> + std::fmt::Debug>(
243 control_socket_path: T,
244 display_id: u32,
245 mouse_mode: MouseMode,
246 ) -> ModifyGpuResult {
247 let request = VmRequest::GpuCommand(GpuControlCommand::SetDisplayMouseMode {
248 display_id,
249 mouse_mode,
250 });
251 handle_request(&request, control_socket_path)
252 .map_err(|_| ModifyGpuError::SocketFailed)?
253 .into()
254 }
255