• 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::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