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 mod math_util; 6 #[allow(dead_code)] 7 mod message_relay_thread; 8 pub mod surface; 9 mod thread_message_util; 10 mod window; 11 mod window_message_dispatcher; 12 mod window_message_processor; 13 pub mod window_procedure_thread; 14 15 use std::num::NonZeroU32; 16 use std::sync::mpsc::channel; 17 #[cfg(feature = "kiwi")] 18 use std::sync::Arc; 19 use std::sync::Weak; 20 use std::time::Duration; 21 22 use anyhow::bail; 23 use anyhow::Context; 24 use anyhow::Result; 25 use base::error; 26 use base::AsRawDescriptor; 27 use base::Event; 28 use base::EventWaitResult; 29 use base::RawDescriptor; 30 #[cfg(feature = "kiwi")] 31 use base::Tube; 32 use euclid::size2; 33 use euclid::Size2D; 34 use math_util::Size2DCheckedCast; 35 use metrics::Metrics; 36 pub use surface::NoopSurface as Surface; 37 #[cfg(feature = "kiwi")] 38 use sync::Mutex; 39 use vm_control::gpu::DisplayMode; 40 use vm_control::gpu::DisplayParameters; 41 use window_message_processor::DisplaySendToWndProc; 42 pub use window_procedure_thread::WindowProcedureThread; 43 44 use crate::DisplayT; 45 use crate::EventDevice; 46 use crate::GpuDisplayError; 47 use crate::GpuDisplayResult; 48 use crate::GpuDisplaySurface; 49 use crate::SurfaceType; 50 use crate::SysDisplayT; 51 52 pub(crate) type ObjectId = NonZeroU32; 53 54 pub struct VirtualDisplaySpace; 55 pub struct HostWindowSpace; 56 57 #[derive(Clone)] 58 pub struct DisplayProperties { 59 pub start_hidden: bool, 60 pub is_fullscreen: bool, 61 pub window_width: u32, 62 pub window_height: u32, 63 } 64 65 impl From<&DisplayParameters> for DisplayProperties { from(params: &DisplayParameters) -> Self66 fn from(params: &DisplayParameters) -> Self { 67 let is_fullscreen = matches!(params.mode, DisplayMode::BorderlessFullScreen(_)); 68 let (window_width, window_height) = params.get_window_size(); 69 70 Self { 71 start_hidden: params.hidden, 72 is_fullscreen, 73 window_width, 74 window_height, 75 } 76 } 77 } 78 79 pub struct DisplayWin { 80 wndproc_thread: WindowProcedureThread<Surface>, 81 display_closed_event: Event, 82 win_metrics: Option<Weak<Metrics>>, 83 display_properties: DisplayProperties, 84 is_surface_created: bool, 85 } 86 87 impl DisplayWin { new( wndproc_thread: WindowProcedureThread<Surface>, win_metrics: Option<Weak<Metrics>>, display_properties: DisplayProperties, ) -> Result<DisplayWin, GpuDisplayError>88 pub fn new( 89 wndproc_thread: WindowProcedureThread<Surface>, 90 win_metrics: Option<Weak<Metrics>>, 91 display_properties: DisplayProperties, 92 ) -> Result<DisplayWin, GpuDisplayError> { 93 // The display should be closed once the WndProc thread terminates. 94 let display_closed_event = 95 wndproc_thread 96 .try_clone_thread_terminated_event() 97 .map_err(|e| { 98 error!("Failed to create DisplayWin: {:?}", e); 99 GpuDisplayError::Allocate 100 })?; 101 Ok(Self { 102 wndproc_thread, 103 display_closed_event, 104 win_metrics, 105 display_properties, 106 is_surface_created: false, 107 }) 108 } 109 110 /// Posts a create surface command to the WndProc thread and waits until the creation finishes 111 /// to check the result. create_surface_internal( &mut self, virtual_display_size: Size2D<i32, VirtualDisplaySpace>, ) -> Result<()>112 fn create_surface_internal( 113 &mut self, 114 virtual_display_size: Size2D<i32, VirtualDisplaySpace>, 115 ) -> Result<()> { 116 let metrics = self.win_metrics.clone(); 117 let display_properties = self.display_properties.clone(); 118 // This function should not return until surface creation finishes. Besides, we would like 119 // to know if the creation succeeds. Hence, we use channels to wait to see the result. 120 let (result_sender, result_receiver) = channel(); 121 122 // Post a message to the WndProc thread to create the surface. 123 self.wndproc_thread 124 .post_display_command(DisplaySendToWndProc::CreateSurface { 125 function: Box::new(move |window, display_event_dispatcher| { 126 Surface::create( 127 window, 128 &virtual_display_size, 129 metrics, 130 &display_properties, 131 display_event_dispatcher, 132 ) 133 }), 134 callback: Box::new(move |success| { 135 if let Err(e) = result_sender.send(success) { 136 error!("Failed to send surface creation result: {}", e); 137 } 138 }), 139 })?; 140 141 // Block until the surface creation finishes and check the result. 142 match result_receiver.recv() { 143 Ok(true) => Ok(()), 144 Ok(false) => bail!("WndProc thread failed to create surface!"), 145 Err(e) => bail!("Failed to receive surface creation result: {}", e), 146 } 147 } 148 import_event_device_internal( &mut self, event_device_id: u32, event_device: EventDevice, ) -> Result<()>149 fn import_event_device_internal( 150 &mut self, 151 event_device_id: u32, 152 event_device: EventDevice, 153 ) -> Result<()> { 154 match ObjectId::new(event_device_id) { 155 Some(event_device_id) => { 156 self.wndproc_thread 157 .post_display_command(DisplaySendToWndProc::ImportEventDevice { 158 event_device_id, 159 event_device, 160 }) 161 .context("Failed to send ImportEventDevice message")?; 162 Ok(()) 163 } 164 None => bail!("{} cannot be converted to ObjectId", event_device_id), 165 } 166 } 167 } 168 169 impl AsRawDescriptor for DisplayWin { 170 /// Event handling is done on the GPU worker thread on other platforms. However, due to the way 171 /// Windows GUI system works, we have to do that on the WndProc thread instead, and we only 172 /// notify the event loop in the GPU worker thread of the display closure event. as_raw_descriptor(&self) -> RawDescriptor173 fn as_raw_descriptor(&self) -> RawDescriptor { 174 self.display_closed_event.as_raw_descriptor() 175 } 176 } 177 178 impl DisplayT for DisplayWin { create_surface( &mut self, parent_surface_id: Option<u32>, _surface_id: u32, virtual_display_width: u32, virtual_display_height: u32, surface_type: SurfaceType, ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>>179 fn create_surface( 180 &mut self, 181 parent_surface_id: Option<u32>, 182 _surface_id: u32, 183 virtual_display_width: u32, 184 virtual_display_height: u32, 185 surface_type: SurfaceType, 186 ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>> { 187 if parent_surface_id.is_some() { 188 return Err(GpuDisplayError::Unsupported); 189 } 190 191 if !matches!(surface_type, SurfaceType::Scanout) { 192 return Err(GpuDisplayError::Unsupported); 193 } 194 195 // Gfxstream allows for attaching a window only once along the initialization, so we only 196 // create the surface once. See details in b/179319775. 197 if !self.is_surface_created { 198 match self.create_surface_internal( 199 size2(virtual_display_width, virtual_display_height).checked_cast(), 200 ) { 201 Ok(_) => self.is_surface_created = true, 202 Err(e) => { 203 error!("Failed to create surface: {:?}", e); 204 return Err(GpuDisplayError::Allocate); 205 } 206 } 207 } 208 209 Ok(Box::new(SurfaceWin { 210 display_closed_event: self.display_closed_event.try_clone().map_err(|e| { 211 error!("Failed to clone display_closed_event: {}", e); 212 GpuDisplayError::Allocate 213 })?, 214 })) 215 } 216 } 217 218 impl SysDisplayT for DisplayWin { import_event_device( &mut self, event_device_id: u32, event_device: EventDevice, ) -> GpuDisplayResult<()>219 fn import_event_device( 220 &mut self, 221 event_device_id: u32, 222 event_device: EventDevice, 223 ) -> GpuDisplayResult<()> { 224 self.import_event_device_internal(event_device_id, event_device) 225 .map_err(|e| { 226 GpuDisplayError::FailedEventDeviceImport(format!( 227 "Failed to import event device (ID: {}): {:?}", 228 event_device_id, e 229 )) 230 }) 231 } 232 } 233 234 /// The display logic for Windows is quite different from other platforms since display events are 235 /// not handled on the GPU worker thread, but handled by `Surface` class that lives in the WndProc 236 /// thread. `SurfaceWin` will live in the GPU worker thread and provide limited functionalities. 237 pub(crate) struct SurfaceWin { 238 display_closed_event: Event, 239 } 240 241 impl GpuDisplaySurface for SurfaceWin { 242 /// The entire VM will be shut down when this function returns true. We don't want that happen 243 /// until we know our display is expected to be closed. close_requested(&self) -> bool244 fn close_requested(&self) -> bool { 245 match self 246 .display_closed_event 247 .wait_timeout(Duration::from_secs(0)) 248 { 249 Ok(EventWaitResult::Signaled) => true, 250 Ok(EventWaitResult::TimedOut) => false, 251 Err(e) => { 252 error!("Failed to read whether display is closed: {}", e); 253 false 254 } 255 } 256 } 257 } 258