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 keyboard_input_manager; 6 mod math_util; 7 mod mouse_input_manager; 8 pub mod surface; 9 mod virtual_display_manager; 10 mod window; 11 mod window_manager; 12 mod window_message_dispatcher; 13 mod window_message_processor; 14 pub mod window_procedure_thread; 15 16 use std::collections::HashMap; 17 use std::num::NonZeroU32; 18 use std::rc::Rc; 19 use std::sync::mpsc::channel; 20 use std::sync::Arc; 21 use std::sync::Weak; 22 use std::time::Duration; 23 24 use anyhow::bail; 25 use anyhow::format_err; 26 #[cfg(feature = "vulkan_display")] 27 use anyhow::Context; 28 use anyhow::Result; 29 use base::error; 30 use base::info; 31 use base::warn; 32 use base::AsRawDescriptor; 33 use base::Descriptor; 34 use base::Event; 35 use base::EventWaitResult; 36 use base::RawDescriptor; 37 use base::ReadNotifier; 38 use base::SendTube; 39 use metrics::sys::windows::Metrics; 40 pub use surface::Surface; 41 use sync::Mutex; 42 use sync::Waitable; 43 use vm_control::gpu::DisplayParameters; 44 use vm_control::ModifyWaitContext; 45 use window_message_processor::DisplaySendToWndProc; 46 pub use window_procedure_thread::WindowProcedureThread; 47 pub use window_procedure_thread::WindowProcedureThreadBuilder; 48 49 #[cfg(feature = "vulkan_display")] 50 use crate::gpu_display_win::window::BasicWindow; 51 #[cfg(feature = "vulkan_display")] 52 use crate::vulkan::VulkanDisplay; 53 use crate::DisplayExternalResourceImport; 54 use crate::DisplayT; 55 use crate::EventDevice; 56 use crate::FlipToExtraInfo; 57 use crate::GpuDisplayError; 58 use crate::GpuDisplayResult; 59 use crate::GpuDisplaySurface; 60 use crate::MouseMode; 61 use crate::SemaphoreTimepoint; 62 use crate::SurfaceType; 63 use crate::SysDisplayT; 64 use crate::VulkanCreateParams; 65 66 pub(crate) type ObjectId = NonZeroU32; 67 68 pub struct VirtualDisplaySpace; 69 pub struct HostWindowSpace; 70 71 pub enum VulkanDisplayWrapper { 72 Uninitialized, 73 #[cfg(feature = "vulkan_display")] 74 Initialized(VulkanDisplay), 75 } 76 77 pub struct DisplayWin { 78 wndproc_thread: Rc<WindowProcedureThread>, 79 close_requested_event: Event, 80 win_metrics: Option<Weak<Metrics>>, 81 is_surface_created: bool, 82 #[allow(dead_code)] 83 gpu_display_wait_descriptor_ctrl: SendTube, 84 event_device_wait_descriptor_requests: Vec<ModifyWaitContext>, 85 vulkan_displays: HashMap<u32, Arc<Mutex<VulkanDisplayWrapper>>>, 86 #[allow(dead_code)] 87 vulkan_display_create_params: Option<VulkanCreateParams>, 88 } 89 90 impl DisplayWin { new( wndproc_thread: WindowProcedureThread, win_metrics: Option<Weak<Metrics>>, gpu_display_wait_descriptor_ctrl: SendTube, vulkan_display_create_params: Option<VulkanCreateParams>, ) -> Result<DisplayWin, GpuDisplayError>91 pub fn new( 92 wndproc_thread: WindowProcedureThread, 93 win_metrics: Option<Weak<Metrics>>, 94 gpu_display_wait_descriptor_ctrl: SendTube, 95 vulkan_display_create_params: Option<VulkanCreateParams>, 96 ) -> Result<DisplayWin, GpuDisplayError> { 97 let close_requested_event = 98 wndproc_thread 99 .try_clone_close_requested_event() 100 .map_err(|e| { 101 error!("Failed to create DisplayWin: {:?}", e); 102 GpuDisplayError::Allocate 103 })?; 104 Ok(Self { 105 wndproc_thread: Rc::new(wndproc_thread), 106 close_requested_event, 107 win_metrics, 108 is_surface_created: false, 109 gpu_display_wait_descriptor_ctrl, 110 event_device_wait_descriptor_requests: Vec::new(), 111 vulkan_displays: HashMap::new(), 112 vulkan_display_create_params, 113 }) 114 } 115 116 /// Posts a create surface command to the WndProc thread and waits until the creation finishes 117 /// to check the result. create_surface_internal( &mut self, surface_id: u32, scanout_id: u32, display_params: &DisplayParameters, ) -> Result<Arc<Mutex<VulkanDisplayWrapper>>>118 fn create_surface_internal( 119 &mut self, 120 surface_id: u32, 121 scanout_id: u32, 122 display_params: &DisplayParameters, 123 ) -> Result<Arc<Mutex<VulkanDisplayWrapper>>> { 124 let display_params_clone = display_params.clone(); 125 let metrics = self.win_metrics.clone(); 126 #[cfg(feature = "vulkan_display")] 127 let vulkan_create_params = self.vulkan_display_create_params.clone(); 128 // This function should not return until surface creation finishes. Besides, we would like 129 // to know if the creation succeeds. Hence, we use channels to wait to see the result. 130 let (result_sender, result_receiver) = channel(); 131 #[allow(unused_variables)] 132 let (vulkan_display_sender, vulkan_display_receiver) = channel(); 133 134 // Post a message to the WndProc thread to create the surface. 135 self.wndproc_thread 136 .post_display_command(DisplaySendToWndProc::CreateSurface { 137 scanout_id, 138 function: Box::new(move |window, display_event_dispatcher| { 139 #[cfg(feature = "vulkan_display")] 140 let vulkan_display = { 141 let create_display_closure = 142 |VulkanCreateParams { 143 vulkan_library, 144 device_uuid, 145 driver_uuid, 146 }| { 147 // SAFETY: Safe because vulkan display lives longer than window 148 // (because for Windows, we keep the 149 // windows alive for the entire life of the 150 // emulator). 151 unsafe { 152 let initial_host_viewport_size = window 153 .get_client_rect() 154 .with_context(|| "retrieve window client area size")? 155 .size; 156 VulkanDisplay::new( 157 vulkan_library, 158 window.handle() as _, 159 &initial_host_viewport_size.cast_unit(), 160 device_uuid, 161 driver_uuid, 162 ) 163 .with_context(|| "create vulkan display") 164 } 165 }; 166 let vulkan_display = vulkan_create_params 167 .map(create_display_closure) 168 .transpose()?; 169 let vulkan_display = match vulkan_display { 170 Some(vulkan_display) => { 171 VulkanDisplayWrapper::Initialized(vulkan_display) 172 } 173 None => VulkanDisplayWrapper::Uninitialized, 174 }; 175 let vulkan_display = Arc::new(Mutex::new(vulkan_display)); 176 vulkan_display_sender 177 .send(Arc::clone(&vulkan_display)) 178 .map_err(|_| { 179 format_err!("Failed to send vulkan display back to caller.") 180 })?; 181 vulkan_display 182 }; 183 184 #[cfg(not(feature = "vulkan_display"))] 185 let vulkan_display = Arc::new(Mutex::new(VulkanDisplayWrapper::Uninitialized)); 186 187 Surface::new( 188 surface_id, 189 window, 190 metrics, 191 &display_params_clone, 192 display_event_dispatcher, 193 vulkan_display, 194 ) 195 }), 196 callback: Box::new(move |success| { 197 if let Err(e) = result_sender.send(success) { 198 error!("Failed to send surface creation result: {}", e); 199 } 200 }), 201 })?; 202 203 // Block until the surface creation finishes and check the result. 204 match result_receiver.recv() { 205 Ok(true) => vulkan_display_receiver.recv().map_err(|_| { 206 format_err!( 207 "Failed to receive the vulkan display from the surface creation routine." 208 ) 209 }), 210 Ok(false) => bail!("WndProc thread failed to create surface!"), 211 Err(e) => bail!("Failed to receive surface creation result: {}", e), 212 } 213 } 214 import_event_device_internal( &mut self, event_device_id: u32, event_device: EventDevice, ) -> Result<()>215 fn import_event_device_internal( 216 &mut self, 217 event_device_id: u32, 218 event_device: EventDevice, 219 ) -> Result<()> { 220 match ObjectId::new(event_device_id) { 221 Some(event_device_id) => { 222 // This is safe because the winproc thread (which owns the event device after we 223 // send it there below) will be dropped before the GPU worker thread (which is 224 // where we're sending this descriptor). 225 let req = ModifyWaitContext::Add(Descriptor( 226 event_device.get_read_notifier().as_raw_descriptor(), 227 )); 228 229 if let Err(e) = self.wndproc_thread.post_display_command( 230 DisplaySendToWndProc::ImportEventDevice { 231 event_device_id, 232 event_device, 233 }, 234 ) { 235 bail!("Failed to post ImportEventDevice message: {:?}", e); 236 } 237 238 if self.is_surface_created { 239 if let Err(e) = self.gpu_display_wait_descriptor_ctrl.send(&req) { 240 bail!( 241 "failed to send event device descriptor to \ 242 GPU worker's wait context: {:?}", 243 e 244 ) 245 } 246 } else { 247 self.event_device_wait_descriptor_requests.push(req); 248 } 249 250 Ok(()) 251 } 252 None => bail!("{} cannot be converted to ObjectId", event_device_id), 253 } 254 } 255 } 256 257 impl AsRawDescriptor for DisplayWin { 258 /// Event handling is done on the GPU worker thread on other platforms. However, due to the way 259 /// Windows GUI system works, we have to do that on the WndProc thread instead, and we only 260 /// notify the event loop in the GPU worker thread of the display closure event. as_raw_descriptor(&self) -> RawDescriptor261 fn as_raw_descriptor(&self) -> RawDescriptor { 262 self.close_requested_event.as_raw_descriptor() 263 } 264 } 265 266 impl DisplayT for DisplayWin { create_surface( &mut self, parent_surface_id: Option<u32>, surface_id: u32, scanout_id: Option<u32>, display_params: &DisplayParameters, surface_type: SurfaceType, ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>>267 fn create_surface( 268 &mut self, 269 parent_surface_id: Option<u32>, 270 surface_id: u32, 271 scanout_id: Option<u32>, 272 display_params: &DisplayParameters, 273 surface_type: SurfaceType, 274 ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>> { 275 if parent_surface_id.is_some() { 276 return Err(GpuDisplayError::Unsupported); 277 } 278 279 if !matches!(surface_type, SurfaceType::Scanout) { 280 return Err(GpuDisplayError::Unsupported); 281 } 282 283 // Gfxstream allows for attaching a window only once along the initialization, so we only 284 // create the surface once. See details in b/179319775. 285 let vulkan_display = match self.create_surface_internal( 286 surface_id, 287 scanout_id.expect("scanout id is required"), 288 display_params, 289 ) { 290 Err(e) => { 291 error!("Failed to create surface: {:?}", e); 292 return Err(GpuDisplayError::Allocate); 293 } 294 Ok(display) => display, 295 }; 296 self.is_surface_created = true; 297 self.vulkan_displays 298 .insert(surface_id, Arc::clone(&vulkan_display)); 299 300 // Now that the window is ready, we can start listening for inbound (guest -> host) events 301 // on our event devices. 302 for req in self.event_device_wait_descriptor_requests.drain(..) { 303 if let Err(e) = self.gpu_display_wait_descriptor_ctrl.send(&req) { 304 error!( 305 "failed to send event device descriptor to GPU worker's wait context: {:?}", 306 e 307 ); 308 return Err(GpuDisplayError::FailedEventDeviceListen(e)); 309 } 310 } 311 312 Ok(Box::new(SurfaceWin { 313 surface_id, 314 wndproc_thread: Rc::downgrade(&self.wndproc_thread), 315 close_requested_event: self.close_requested_event.try_clone().map_err(|e| { 316 error!("Failed to clone close_requested_event: {}", e); 317 GpuDisplayError::Allocate 318 })?, 319 vulkan_display, 320 })) 321 } 322 import_resource( &mut self, #[allow(unused_variables)] import_id: u32, surface_id: u32, #[allow(unused_variables)] external_display_resource: DisplayExternalResourceImport, ) -> Result<()>323 fn import_resource( 324 &mut self, 325 #[allow(unused_variables)] import_id: u32, 326 surface_id: u32, 327 #[allow(unused_variables)] external_display_resource: DisplayExternalResourceImport, 328 ) -> Result<()> { 329 match self.vulkan_displays.get(&surface_id) { 330 Some(vulkan_display) => match *vulkan_display.lock() { 331 #[cfg(feature = "vulkan_display")] 332 VulkanDisplayWrapper::Initialized(ref mut vulkan_display) => { 333 match external_display_resource { 334 DisplayExternalResourceImport::VulkanImage { 335 descriptor, 336 metadata, 337 } => { 338 vulkan_display.import_image(import_id, descriptor, metadata)?; 339 } 340 DisplayExternalResourceImport::VulkanTimelineSemaphore { descriptor } => { 341 vulkan_display.import_semaphore(import_id, descriptor)?; 342 } 343 DisplayExternalResourceImport::Dmabuf { .. } => { 344 bail!("gpu_display_win does not support importing dmabufs") 345 } 346 } 347 Ok(()) 348 } 349 VulkanDisplayWrapper::Uninitialized => { 350 bail!("VulkanDisplay is not initialized for this surface") 351 } 352 }, 353 None => { 354 bail!("No VulkanDisplay for surface id {}", surface_id) 355 } 356 } 357 } 358 359 #[allow(unused_variables)] release_import(&mut self, surface_id: u32, import_id: u32)360 fn release_import(&mut self, surface_id: u32, import_id: u32) { 361 #[cfg(feature = "vulkan_display")] 362 if let Some(vulkan_display) = self.vulkan_displays.get(&surface_id) { 363 if let VulkanDisplayWrapper::Initialized(ref mut vulkan_display) = 364 *vulkan_display.lock() 365 { 366 vulkan_display.delete_imported_image_or_semaphore(import_id); 367 } 368 } 369 } 370 } 371 372 impl SysDisplayT for DisplayWin { import_event_device( &mut self, event_device_id: u32, event_device: EventDevice, ) -> GpuDisplayResult<()>373 fn import_event_device( 374 &mut self, 375 event_device_id: u32, 376 event_device: EventDevice, 377 ) -> GpuDisplayResult<()> { 378 self.import_event_device_internal(event_device_id, event_device) 379 .map_err(|e| { 380 GpuDisplayError::FailedEventDeviceImport(format!( 381 "Failed to import event device (ID: {}): {:?}", 382 event_device_id, e 383 )) 384 }) 385 } 386 handle_event_device(&mut self, event_device_id: u32)387 fn handle_event_device(&mut self, event_device_id: u32) { 388 match ObjectId::new(event_device_id) { 389 Some(event_device_id) => { 390 if let Err(e) = self 391 .wndproc_thread 392 .post_display_command(DisplaySendToWndProc::HandleEventDevice(event_device_id)) 393 { 394 error!( 395 "Failed to route guest -> host input_event; event device (ID: {:?}): {:?}", 396 event_device_id, e 397 ); 398 } 399 } 400 None => error!( 401 "Failed to route guest -> host input_event; {} cannot be converted to ObjectId", 402 event_device_id 403 ), 404 } 405 } 406 } 407 408 /// The display logic for Windows is quite different from other platforms since display events are 409 /// not handled on the GPU worker thread, but handled by `Surface` class that lives in the WndProc 410 /// thread. `SurfaceWin` will live in the GPU worker thread and provide limited functionalities. 411 pub(crate) struct SurfaceWin { 412 surface_id: u32, 413 wndproc_thread: std::rc::Weak<WindowProcedureThread>, 414 close_requested_event: Event, 415 #[allow(dead_code)] 416 vulkan_display: Arc<Mutex<VulkanDisplayWrapper>>, 417 } 418 419 impl GpuDisplaySurface for SurfaceWin { 420 /// The entire VM will be shut down when this function returns true. We don't want that happen 421 /// until we know our display is expected to be closed. close_requested(&self) -> bool422 fn close_requested(&self) -> bool { 423 match self 424 .close_requested_event 425 .wait_timeout(Duration::from_secs(0)) 426 { 427 Ok(EventWaitResult::Signaled) => true, 428 Ok(EventWaitResult::TimedOut) => false, 429 Err(e) => { 430 error!("Failed to read whether display is closed: {}", e); 431 false 432 } 433 } 434 } 435 set_mouse_mode(&mut self, mouse_mode: MouseMode)436 fn set_mouse_mode(&mut self, mouse_mode: MouseMode) { 437 if let Some(wndproc_thread) = self.wndproc_thread.upgrade() { 438 if let Err(e) = 439 wndproc_thread.post_display_command(DisplaySendToWndProc::SetMouseMode { 440 surface_id: self.surface_id, 441 mouse_mode, 442 }) 443 { 444 warn!("Failed to post SetMouseMode message: {:?}", e); 445 } 446 } 447 } 448 449 #[cfg(not(feature = "vulkan_display"))] flip_to( &mut self, _import_id: u32, _acquire_timepoint: Option<SemaphoreTimepoint>, _release_timepoint: Option<SemaphoreTimepoint>, _extra_info: Option<FlipToExtraInfo>, ) -> Result<Waitable>450 fn flip_to( 451 &mut self, 452 _import_id: u32, 453 _acquire_timepoint: Option<SemaphoreTimepoint>, 454 _release_timepoint: Option<SemaphoreTimepoint>, 455 _extra_info: Option<FlipToExtraInfo>, 456 ) -> Result<Waitable> { 457 bail!("vulkan_display feature is not enabled") 458 } 459 460 #[cfg(feature = "vulkan_display")] flip_to( &mut self, import_id: u32, acquire_timepoint: Option<SemaphoreTimepoint>, release_timepoint: Option<SemaphoreTimepoint>, extra_info: Option<FlipToExtraInfo>, ) -> Result<Waitable>461 fn flip_to( 462 &mut self, 463 import_id: u32, 464 acquire_timepoint: Option<SemaphoreTimepoint>, 465 release_timepoint: Option<SemaphoreTimepoint>, 466 extra_info: Option<FlipToExtraInfo>, 467 ) -> Result<Waitable> { 468 let last_layout_transition = match extra_info { 469 Some(FlipToExtraInfo::Vulkan { 470 old_layout, 471 new_layout, 472 }) => (old_layout, new_layout), 473 None => { 474 bail!("vulkan display flip_to requires old and new layout in extra_info") 475 } 476 }; 477 478 let release_timepoint = 479 release_timepoint.ok_or(anyhow::anyhow!("release timepoint must be non-None"))?; 480 481 match *self.vulkan_display.lock() { 482 VulkanDisplayWrapper::Initialized(ref mut vulkan_display) => vulkan_display.post( 483 import_id, 484 last_layout_transition, 485 acquire_timepoint, 486 release_timepoint, 487 ), 488 VulkanDisplayWrapper::Uninitialized => { 489 bail!("VulkanDisplay is not initialized for this surface") 490 } 491 } 492 } 493 } 494 495 impl Drop for SurfaceWin { drop(&mut self)496 fn drop(&mut self) { 497 info!("Dropping surface {}", self.surface_id); 498 // Let the WndProc thread release `Surface` and return the associated window to the pool. 499 // If the WndProc thread has already done so and has shut down, it is benign to hit an error 500 // below since we can no longer deliver this notification. 501 if let Some(wndproc_thread) = self.wndproc_thread.upgrade() { 502 if let Err(e) = 503 wndproc_thread.post_display_command(DisplaySendToWndProc::ReleaseSurface { 504 surface_id: self.surface_id, 505 }) 506 { 507 warn!( 508 "Failed to post ReleaseSurface message (benign if message loop has \ 509 shut down): {:?}", 510 e 511 ); 512 } 513 } 514 } 515 } 516 517 #[cfg(test)] 518 mod tests { 519 use base::Tube; 520 521 use super::*; 522 523 #[test] can_create_2_window_proc_threads()524 fn can_create_2_window_proc_threads() { 525 let threads = (0..2) 526 .map(|_| { 527 let (main_ime_tube, _device_ime_tube) = 528 Tube::pair().expect("failed to create IME tube"); 529 let wndproc_thread_builder = WindowProcedureThread::builder(); 530 #[cfg(feature = "kiwi")] 531 let wndproc_thread_builder = { 532 let mut wndproc_thread_builder = wndproc_thread_builder; 533 wndproc_thread_builder 534 .set_max_num_windows(1) 535 .set_display_tube(None) 536 .set_ime_tube(Some(_device_ime_tube)); 537 wndproc_thread_builder 538 }; 539 ( 540 wndproc_thread_builder.start_thread().unwrap(), 541 main_ime_tube, 542 ) 543 }) 544 .collect::<Vec<_>>(); 545 drop(threads); 546 } 547 } 548