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