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::marker::PhantomData;
6
7 use base::info;
8 use serde::Deserialize;
9 use serde::Serialize;
10 use winapi::um::winuser::GetSystemMetrics;
11 use winapi::um::winuser::SM_CXSCREEN;
12 use winapi::um::winuser::SM_CYSCREEN;
13
14 use crate::gpu::DisplayModeTrait;
15
16 const DISPLAY_WIDTH_SOFT_MAX: u32 = 1920;
17 const DISPLAY_HEIGHT_SOFT_MAX: u32 = 1080;
18
19 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
20 #[serde(rename_all = "snake_case")]
21 pub enum WinDisplayMode<T> {
22 Windowed(u32, u32),
23 BorderlessFullScreen(#[serde(skip)] PhantomData<T>),
24 }
25
26 impl<T: ProvideDisplayData> DisplayModeTrait for WinDisplayMode<T> {
get_window_size(&self) -> (u32, u32)27 fn get_window_size(&self) -> (u32, u32) {
28 match self {
29 Self::Windowed(width, height) => (*width, *height),
30 Self::BorderlessFullScreen(_) => T::get_host_display_size(),
31 }
32 }
33
get_virtual_display_size(&self) -> (u32, u32)34 fn get_virtual_display_size(&self) -> (u32, u32) {
35 let (width, height) = self.get_window_size();
36 let (width, height) = adjust_virtual_display_size(width, height);
37 info!("Guest display size: {}x{}", width, height);
38 (width, height)
39 }
40 }
41
42 /// Trait for returning host display data such as resolution. Tests may overwrite this to specify
43 /// display data rather than rely on properties of the actual display device.
44 trait ProvideDisplayData {
get_host_display_size() -> (u32, u32)45 fn get_host_display_size() -> (u32, u32);
46 }
47
48 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
49 pub struct DisplayDataProvider;
50
51 impl ProvideDisplayData for DisplayDataProvider {
get_host_display_size() -> (u32, u32)52 fn get_host_display_size() -> (u32, u32) {
53 // Safe because we're passing valid values and screen size won't exceed u32 range.
54 let (width, height) = unsafe {
55 (
56 GetSystemMetrics(SM_CXSCREEN) as u32,
57 GetSystemMetrics(SM_CYSCREEN) as u32,
58 )
59 };
60 // Note: This is the size of the host's display. The guest display size given by
61 // (width, height) may be smaller if we are letterboxing.
62 info!("Host display size: {}x{}", width, height);
63 (width, height)
64 }
65 }
66
adjust_virtual_display_size(width: u32, height: u32) -> (u32, u32)67 fn adjust_virtual_display_size(width: u32, height: u32) -> (u32, u32) {
68 let width = std::cmp::min(width, DISPLAY_WIDTH_SOFT_MAX);
69 let height = std::cmp::min(height, DISPLAY_HEIGHT_SOFT_MAX);
70 // Widths that aren't a multiple of 8 break gfxstream: b/156110663.
71 let width = width - (width % 8);
72 (width, height)
73 }
74
75 #[cfg(test)]
76 mod tests {
77 use super::*;
78
79 #[test]
borderless_full_screen_virtual_window_width_should_be_multiple_of_8()80 fn borderless_full_screen_virtual_window_width_should_be_multiple_of_8() {
81 struct MockDisplayDataProvider;
82
83 impl ProvideDisplayData for MockDisplayDataProvider {
84 fn get_host_display_size() -> (u32, u32) {
85 (1366, 768)
86 }
87 }
88
89 let mode = WinDisplayMode::<MockDisplayDataProvider>::BorderlessFullScreen(PhantomData);
90 let (width, _) = mode.get_virtual_display_size();
91 assert_eq!(width % 8, 0);
92 }
93
94 #[test]
borderless_full_screen_virtual_window_size_should_be_smaller_than_soft_max()95 fn borderless_full_screen_virtual_window_size_should_be_smaller_than_soft_max() {
96 struct MockDisplayDataProvider;
97
98 impl ProvideDisplayData for MockDisplayDataProvider {
99 fn get_host_display_size() -> (u32, u32) {
100 (DISPLAY_WIDTH_SOFT_MAX + 1, DISPLAY_HEIGHT_SOFT_MAX + 1)
101 }
102 }
103
104 let mode = WinDisplayMode::<MockDisplayDataProvider>::BorderlessFullScreen(PhantomData);
105 let (width, height) = mode.get_virtual_display_size();
106 assert!(width <= DISPLAY_WIDTH_SOFT_MAX);
107 assert!(height <= DISPLAY_HEIGHT_SOFT_MAX);
108 }
109 }
110