xref: /aosp_15_r20/external/crosvm/gpu_display/src/gpu_display_win/mod.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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