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::*;
17
18 pub const DEFAULT_DISPLAY_WIDTH: u32 = 1280;
19 pub const DEFAULT_DISPLAY_HEIGHT: u32 = 1024;
20 pub const DEFAULT_DPI: u32 = 320;
21 pub const DEFAULT_REFRESH_RATE: u32 = 60;
22
default_refresh_rate() -> u3223 fn default_refresh_rate() -> u32 {
24 DEFAULT_REFRESH_RATE
25 }
26
27 /// Trait that the platform-specific type `DisplayMode` needs to implement.
28 pub(crate) trait DisplayModeTrait {
29 /// Returns the initial host window size.
get_window_size(&self) -> (u32, u32)30 fn get_window_size(&self) -> (u32, u32);
31
32 /// Returns the virtual display size used for creating the display device.
33 ///
34 /// This may be different from the initial host window size since different display backends may
35 /// have different alignment requirements on it.
get_virtual_display_size(&self) -> (u32, u32)36 fn get_virtual_display_size(&self) -> (u32, u32);
37 }
38
39 impl Default for DisplayMode {
default() -> Self40 fn default() -> Self {
41 Self::Windowed(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
42 }
43 }
44
45 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
46 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
47 pub struct DisplayParameters {
48 #[serde(default)]
49 pub mode: DisplayMode,
50 #[serde(default)]
51 pub hidden: bool,
52 #[serde(default = "default_refresh_rate")]
53 pub refresh_rate: u32,
54 // TODO(b/260101753): `dpi` has to be an `Option` for supporting CLI backward compatibility.
55 // That should be changed once compat fields below are deprecated.
56 pub dpi: Option<(u32, u32)>,
57 // `horizontal-dpi` and `vertical-dpi` are supported for CLI backward compatibility.
58 #[serde(rename = "horizontal-dpi")]
59 pub __horizontal_dpi_compat: Option<u32>,
60 #[serde(rename = "vertical-dpi")]
61 pub __vertical_dpi_compat: Option<u32>,
62 }
63
64 impl DisplayParameters {
new( mode: DisplayMode, hidden: bool, refresh_rate: u32, horizontal_dpi: u32, vertical_dpi: u32, ) -> Self65 pub fn new(
66 mode: DisplayMode,
67 hidden: bool,
68 refresh_rate: u32,
69 horizontal_dpi: u32,
70 vertical_dpi: u32,
71 ) -> Self {
72 Self {
73 mode,
74 hidden,
75 refresh_rate,
76 dpi: Some((horizontal_dpi, vertical_dpi)),
77 __horizontal_dpi_compat: None,
78 __vertical_dpi_compat: None,
79 }
80 }
81
default_with_mode(mode: DisplayMode) -> Self82 pub fn default_with_mode(mode: DisplayMode) -> Self {
83 Self::new(mode, false, DEFAULT_REFRESH_RATE, DEFAULT_DPI, DEFAULT_DPI)
84 }
85
get_window_size(&self) -> (u32, u32)86 pub fn get_window_size(&self) -> (u32, u32) {
87 self.mode.get_window_size()
88 }
89
get_virtual_display_size(&self) -> (u32, u32)90 pub fn get_virtual_display_size(&self) -> (u32, u32) {
91 self.mode.get_virtual_display_size()
92 }
93
horizontal_dpi(&self) -> u3294 pub fn horizontal_dpi(&self) -> u32 {
95 self.dpi.expect("'dpi' is None").0
96 }
97
vertical_dpi(&self) -> u3298 pub fn vertical_dpi(&self) -> u32 {
99 self.dpi.expect("'dpi' is None").1
100 }
101 }
102
103 impl Default for DisplayParameters {
default() -> Self104 fn default() -> Self {
105 Self::default_with_mode(Default::default())
106 }
107 }
108
109 #[derive(Serialize, Deserialize, Debug)]
110 pub enum GpuControlCommand {
111 AddDisplays { displays: Vec<DisplayParameters> },
112 ListDisplays,
113 RemoveDisplays { display_ids: Vec<u32> },
114 }
115
116 #[derive(Serialize, Deserialize, Debug, Clone)]
117 pub enum GpuControlResult {
118 DisplaysUpdated,
119 DisplayList {
120 displays: Map<u32, DisplayParameters>,
121 },
122 TooManyDisplays(usize),
123 NoSuchDisplay {
124 display_id: u32,
125 },
126 }
127
128 impl Display for GpuControlResult {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result129 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130 use self::GpuControlResult::*;
131
132 match self {
133 DisplaysUpdated => write!(f, "displays updated"),
134 DisplayList { displays } => {
135 let json: serde_json::Value = serde_json::json!({
136 "displays": displays,
137 });
138 let json_pretty =
139 serde_json::to_string_pretty(&json).map_err(|_| std::fmt::Error)?;
140 write!(f, "{}", json_pretty)
141 }
142 TooManyDisplays(n) => write!(f, "too_many_displays {}", n),
143 NoSuchDisplay { display_id } => write!(f, "no_such_display {}", display_id),
144 }
145 }
146 }
147
148 pub enum ModifyGpuError {
149 SocketFailed,
150 UnexpectedResponse(VmResponse),
151 UnknownCommand(String),
152 GpuControl(GpuControlResult),
153 }
154
155 impl fmt::Display for ModifyGpuError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157 use self::ModifyGpuError::*;
158
159 match self {
160 SocketFailed => write!(f, "socket failed"),
161 UnexpectedResponse(r) => write!(f, "unexpected response: {}", r),
162 UnknownCommand(c) => write!(f, "unknown display command: `{}`", c),
163 GpuControl(e) => write!(f, "{}", e),
164 }
165 }
166 }
167
168 pub type ModifyGpuResult = std::result::Result<GpuControlResult, ModifyGpuError>;
169
170 impl From<VmResponse> for ModifyGpuResult {
from(response: VmResponse) -> Self171 fn from(response: VmResponse) -> Self {
172 match response {
173 VmResponse::GpuResponse(gpu_response) => Ok(gpu_response),
174 r => Err(ModifyGpuError::UnexpectedResponse(r)),
175 }
176 }
177 }
178
do_gpu_display_add<T: AsRef<Path> + std::fmt::Debug>( control_socket_path: T, displays: Vec<DisplayParameters>, ) -> ModifyGpuResult179 pub fn do_gpu_display_add<T: AsRef<Path> + std::fmt::Debug>(
180 control_socket_path: T,
181 displays: Vec<DisplayParameters>,
182 ) -> ModifyGpuResult {
183 let request = VmRequest::GpuCommand(GpuControlCommand::AddDisplays { displays });
184 handle_request(&request, control_socket_path)
185 .map_err(|_| ModifyGpuError::SocketFailed)?
186 .into()
187 }
188
do_gpu_display_list<T: AsRef<Path> + std::fmt::Debug>( control_socket_path: T, ) -> ModifyGpuResult189 pub fn do_gpu_display_list<T: AsRef<Path> + std::fmt::Debug>(
190 control_socket_path: T,
191 ) -> ModifyGpuResult {
192 let request = VmRequest::GpuCommand(GpuControlCommand::ListDisplays);
193 handle_request(&request, control_socket_path)
194 .map_err(|_| ModifyGpuError::SocketFailed)?
195 .into()
196 }
197
do_gpu_display_remove<T: AsRef<Path> + std::fmt::Debug>( control_socket_path: T, display_ids: Vec<u32>, ) -> ModifyGpuResult198 pub fn do_gpu_display_remove<T: AsRef<Path> + std::fmt::Debug>(
199 control_socket_path: T,
200 display_ids: Vec<u32>,
201 ) -> ModifyGpuResult {
202 let request = VmRequest::GpuCommand(GpuControlCommand::RemoveDisplays { display_ids });
203 handle_request(&request, control_socket_path)
204 .map_err(|_| ModifyGpuError::SocketFailed)?
205 .into()
206 }
207