xref: /aosp_15_r20/external/crosvm/gpu_display/src/vulkan/sys/windows.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2023 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::cell::RefCell;
6 use std::mem::MaybeUninit;
7 use std::ptr::null;
8 use std::ptr::null_mut;
9 use std::sync::mpsc::channel;
10 use std::sync::mpsc::sync_channel;
11 use std::sync::mpsc::Receiver;
12 use std::sync::mpsc::RecvTimeoutError;
13 use std::sync::mpsc::SyncSender;
14 use std::sync::mpsc::TryRecvError;
15 use std::sync::Arc;
16 use std::thread::ThreadId;
17 use std::thread::{self};
18 use std::time::Duration;
19 
20 use anyhow::bail;
21 use anyhow::format_err;
22 use anyhow::Context;
23 use anyhow::Result;
24 use ash::vk;
25 use base::error;
26 use base::info;
27 use base::warn;
28 use base::AsRawDescriptor;
29 use euclid::size2;
30 use euclid::Box2D;
31 use euclid::Size2D;
32 use euclid::UnknownUnit;
33 use sync::Mutex;
34 use vulkano::device::Device;
35 use vulkano::instance::Instance;
36 use vulkano::memory::ExternalMemoryHandleType;
37 use vulkano::memory::ExternalMemoryHandleTypes;
38 use vulkano::memory::MemoryImportInfo;
39 use vulkano::VulkanObject;
40 use win_util::syscall_bail;
41 use win_util::win32_wide_string;
42 use winapi::shared::minwindef::HMODULE;
43 use winapi::shared::minwindef::LPARAM;
44 use winapi::shared::minwindef::LPVOID;
45 use winapi::shared::minwindef::LRESULT;
46 use winapi::shared::minwindef::TRUE;
47 use winapi::shared::minwindef::UINT;
48 use winapi::shared::minwindef::WPARAM;
49 use winapi::shared::windef::HWND;
50 use winapi::shared::windef::RECT;
51 use winapi::shared::winerror::ERROR_CLASS_DOES_NOT_EXIST;
52 use winapi::shared::winerror::ERROR_INVALID_WINDOW_HANDLE;
53 use winapi::shared::winerror::ERROR_SUCCESS;
54 use winapi::um::errhandlingapi::GetLastError;
55 use winapi::um::errhandlingapi::SetLastError;
56 use winapi::um::libloaderapi::GetModuleHandleW;
57 use winapi::um::winuser::CreateWindowExW;
58 use winapi::um::winuser::DefWindowProcW;
59 use winapi::um::winuser::DestroyWindow;
60 use winapi::um::winuser::DispatchMessageW;
61 use winapi::um::winuser::GetClassInfoExW;
62 use winapi::um::winuser::GetClientRect;
63 use winapi::um::winuser::GetMessageW;
64 use winapi::um::winuser::GetWindowLongPtrW;
65 use winapi::um::winuser::MoveWindow;
66 use winapi::um::winuser::PostMessageW;
67 use winapi::um::winuser::PostQuitMessage;
68 use winapi::um::winuser::RegisterClassExW;
69 use winapi::um::winuser::SetWindowLongPtrW;
70 use winapi::um::winuser::CREATESTRUCTW;
71 use winapi::um::winuser::CS_HREDRAW;
72 use winapi::um::winuser::CS_OWNDC;
73 use winapi::um::winuser::CS_VREDRAW;
74 use winapi::um::winuser::GWLP_USERDATA;
75 use winapi::um::winuser::WM_CLOSE;
76 use winapi::um::winuser::WM_DESTROY;
77 use winapi::um::winuser::WM_NCCREATE;
78 use winapi::um::winuser::WM_SIZE;
79 use winapi::um::winuser::WM_USER;
80 use winapi::um::winuser::WNDCLASSEXW;
81 use winapi::um::winuser::WS_CHILD;
82 use winapi::um::winuser::WS_DISABLED;
83 use winapi::um::winuser::WS_EX_NOPARENTNOTIFY;
84 use winapi::um::winuser::WS_VISIBLE;
85 
86 use super::ApplicationState;
87 use super::ApplicationStateBuilder;
88 use super::Surface;
89 use super::Window as WindowT;
90 use super::WindowEvent;
91 use super::WindowEventLoop;
92 
93 pub type NativeWindowType = HWND;
94 
95 #[derive(Copy, Clone, Debug)]
96 struct MessagePacket {
97     msg: UINT,
98     w_param: WPARAM,
99     l_param: LPARAM,
100 }
101 
102 pub struct Window {
103     hwnd: isize,
104     hmodule: isize,
105     owner_thread_id: ThreadId,
106 }
107 
108 impl Window {
109     /// # Safety
110     /// `hwnd` must be a valid `HWND` handle. The ownership of the hwnd is transferred to this
111     /// struct, so that the hwnd shouldn't be destroyed outside this struct.
112     #[deny(unsafe_op_in_unsafe_fn)]
new(hwnd: HWND, hmodule: HMODULE) -> Self113     unsafe fn new(hwnd: HWND, hmodule: HMODULE) -> Self {
114         Self {
115             hwnd: hwnd as isize,
116             hmodule: hmodule as isize,
117             owner_thread_id: thread::current().id(),
118         }
119     }
120 }
121 
122 impl WindowT for Window {
get_inner_size(&self) -> Result<Size2D<u32, euclid::UnknownUnit>>123     fn get_inner_size(&self) -> Result<Size2D<u32, euclid::UnknownUnit>> {
124         let mut rect: RECT = Default::default();
125         // SAFETY: Safe because self.hwnd and rect outlive this function call.
126         if unsafe { GetClientRect(self.hwnd as HWND, &mut rect) } == 0 {
127             syscall_bail!("Failed when calling GetClientRect.");
128         }
129         Ok(size2(rect.right - rect.left, rect.bottom - rect.top)
130             .try_cast()
131             .unwrap_or_else(|| {
132                 panic!(
133                     "Size out of range for the client rect \
134                        {{ left: {} right: {} bottom: {} top: {} }}",
135                     rect.left, rect.right, rect.bottom, rect.top
136                 )
137             }))
138     }
139 
create_vulkan_surface(self: Arc<Self>, instance: Arc<Instance>) -> Result<Arc<Surface>>140     fn create_vulkan_surface(self: Arc<Self>, instance: Arc<Instance>) -> Result<Arc<Surface>> {
141         // SAFETY: Safe because we checked hmodule when we got it, and we created hwnd and checked
142         // it was valid when it was created and we know that self will oulive this Surface
143         // because we pass a clone of the Arc<Self> as the win parameter, which is kept as a
144         // field of the surface.
145         unsafe {
146             Surface::from_win32(
147                 instance,
148                 self.hmodule as HMODULE,
149                 self.hwnd as HWND,
150                 Arc::clone(&self) as _,
151             )
152         }
153         .map_err(|e| e.into())
154     }
155 }
156 
157 impl Drop for Window {
drop(&mut self)158     fn drop(&mut self) {
159         // A thread cannot use DestroyWindow to destroy a window created by a different thread.
160         assert!(thread::current().id() == self.owner_thread_id);
161         // SAFETY: Safe because the safety requirement of new function guarantees that hwnd is a
162         // valid window handle, and we handle the error here.
163         if unsafe { DestroyWindow(self.hwnd as HWND) } == 0 {
164             error!(
165                 "Failed to call DestroyWindow with {}. Error code: {}",
166                 self.hwnd as usize,
167                 // SAFETY: trivially safe
168                 unsafe { GetLastError() }
169             );
170         }
171     }
172 }
173 
174 // Used to notify the event loop thread that the user event queue has at least one user event
175 // available.
176 const WM_USER_USER_EVENT_AVAILABLE: UINT = WM_USER;
177 
178 struct WindowState<AppState: ApplicationState> {
179     app_state: AppState,
180     user_event_rx: Receiver<AppState::UserEvent>,
181     window: Arc<Window>,
182 }
183 
184 #[deny(unsafe_op_in_unsafe_fn)]
185 /// # Safety
186 /// Must only be called inside an associated WNDPROC callback.
handle_window_message<AppState: ApplicationState>( window_state: &RefCell<Option<WindowState<AppState>>>, hwnd: HWND, message: MessagePacket, ) -> Result<LRESULT>187 unsafe fn handle_window_message<AppState: ApplicationState>(
188     window_state: &RefCell<Option<WindowState<AppState>>>,
189     hwnd: HWND,
190     message: MessagePacket,
191 ) -> Result<LRESULT> {
192     if let Some(window_state) = window_state.borrow().as_ref() {
193         assert_eq!(
194             window_state.window.owner_thread_id,
195             std::thread::current().id()
196         );
197     }
198     match message.msg {
199         WM_DESTROY => {
200             info!("Window {:#x} is being destroyed.", hwnd as usize);
201             let window = window_state
202                 .borrow_mut()
203                 .take()
204                 .map(|WindowState { window, .. }| window);
205             if let Some(window) = window {
206                 // This could happen if the window is destroyed without receiving WM_CLOSE.
207                 match Arc::try_unwrap(window) {
208                     // The window is being destroyed. No need to call DestroyWindow again.
209                     Ok(window) => std::mem::forget(window),
210                     Err(window) => {
211                         error!(concat!(
212                             "Not the sole reference to the window. There is a possible resource ",
213                             "leak."
214                         ));
215                         // Prevent other reference from calling DestroyWindow on the window.
216                         std::mem::forget(window);
217                     }
218                 }
219             }
220             // SAFETY: Safe because it will always succeed.
221             unsafe { PostQuitMessage(0) };
222             return Ok(0);
223         }
224         WM_CLOSE => {
225             info!("Window {:#x} is about to be destroyed.", hwnd as usize);
226             let window_state = window_state.borrow_mut().take();
227             drop(window_state);
228             return Ok(0);
229         }
230         WM_SIZE => {
231             let window_state = window_state.borrow();
232             if let Some(window_state) = window_state.as_ref() {
233                 window_state.app_state.process_event(WindowEvent::Resized);
234             } else {
235                 warn!(
236                     concat!(
237                         "The window state is not initialized or has already been destroyed when ",
238                         "handling WM_SIZE. lParam = {:#x}, wParam = {:#x}, HWND = {:#x}."
239                     ),
240                     message.l_param, message.w_param, hwnd as usize
241                 );
242             }
243             return Ok(0);
244         }
245         WM_USER_USER_EVENT_AVAILABLE => {
246             let window_state = window_state.borrow();
247             let window_state = window_state.as_ref().ok_or_else(|| {
248                 format_err!("The window state is not initialized or has already been destroyed.")
249             })?;
250             let user_event = {
251                 // It is unlikely that the message arrives early than the channel receiver is ready.
252                 // However, the message can arrives after the user event is read from the receiver.
253                 // We may even end up with many notification messages in the queue after all the
254                 // user events are handled. In which case, even a short timeout can hurt the
255                 // performance badly. Hence a very small timeout is used.
256                 const TIMEOUT: Duration = Duration::from_nanos(500);
257                 match window_state.user_event_rx.recv_timeout(TIMEOUT) {
258                     Ok(event) => event,
259                     Err(RecvTimeoutError::Timeout) => {
260                         bail!(
261                             "Didn't receive any user events for {:?} after recieved the user \
262                                event available notification. Skip.",
263                             TIMEOUT
264                         );
265                     }
266                     Err(e) => bail!("Failed to receive user event from the channel: {:?}", e),
267                 }
268             };
269             let mut user_event = Some(user_event);
270             loop {
271                 match user_event.take() {
272                     Some(user_event) => window_state
273                         .app_state
274                         .process_event(WindowEvent::User(user_event)),
275                     None => break,
276                 }
277                 match window_state.user_event_rx.try_recv() {
278                     Ok(next_user_event) => user_event = Some(next_user_event),
279                     Err(TryRecvError::Empty) => break,
280                     Err(e) => bail!("Fail to receive more post commands: {:?}.", e),
281                 }
282             }
283         }
284         _ => {}
285     }
286     // SAFETY: Safe because we are processing a message targeting this thread, which is guaranteed
287     // by the safety requirement of this function.
288     Ok(unsafe { DefWindowProcW(hwnd, message.msg, message.w_param, message.l_param) })
289 }
290 
291 #[deny(unsafe_op_in_unsafe_fn)]
wnd_proc<AppState: ApplicationState>( hwnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM, ) -> LRESULT292 unsafe extern "system" fn wnd_proc<AppState: ApplicationState>(
293     hwnd: HWND,
294     msg: UINT,
295     w_param: WPARAM,
296     l_param: LPARAM,
297 ) -> LRESULT {
298     let userdata_ptr = if msg == WM_NCCREATE {
299         // SAFETY: Safe because the lparam for this message is a CREATESTRUCTW.
300         let create_struct = unsafe { (l_param as *const CREATESTRUCTW).as_ref() }
301             .expect("Unexpected null lParam for the WM_NCCREATE message");
302         // SAFETY: Safe because we handle the error cases.
303         unsafe { SetLastError(ERROR_SUCCESS) };
304         // SAFETY: Safe because the GWLP_USERDATA pointer is only used by us, and we check if it's
305         // null each time before we use it. We also know that if the pointer is not null it always
306         // points to a valid RefCell<Option<WindowState>>. This is guaranteed by the safety notes of
307         // create_window.
308         if unsafe { SetWindowLongPtrW(hwnd, GWLP_USERDATA, create_struct.lpCreateParams as isize) }
309             == 0
310         {
311             // SAFETY: trivially safe
312             let error = unsafe { GetLastError() };
313             assert_eq!(
314                 error, ERROR_SUCCESS,
315                 "Failed to set GWLP_USERDATA when initializing the window (Error code {}).",
316                 error
317             );
318         }
319         create_struct.lpCreateParams
320     } else {
321         // SAFETY: trivially safe
322         unsafe { SetLastError(ERROR_SUCCESS) };
323         // SAFETY: Safe because we handle the error cases.
324         let userdata_ptr = unsafe { GetWindowLongPtrW(hwnd, GWLP_USERDATA) };
325         if userdata_ptr == 0 {
326             // SAFETY: trivially safe
327             let error = unsafe { GetLastError() };
328             assert_eq!(
329                 error, ERROR_SUCCESS,
330                 "Failed to get GWLP_USERDATA when handling the message {} (Error code {}).",
331                 msg, error
332             );
333         }
334         userdata_ptr as *mut _
335     };
336 
337     let window_state =
338     // SAFETY: Safe because if the pointer is not null, it always points to a valid
339     // RefCell<Option<WindowState>>. This is guaranteed by the safety notes of create_window.
340         unsafe { (userdata_ptr as *const RefCell<Option<WindowState<AppState>>>).as_ref() };
341     let window_state = if let Some(window_state) = window_state {
342         window_state
343     } else {
344         // SAFETY: Safe because we are processing a message targeting this thread.
345         return unsafe { DefWindowProcW(hwnd, msg, w_param, l_param) };
346     };
347 
348     let message = MessagePacket {
349         msg,
350         w_param,
351         l_param,
352     };
353     // SAFETY: Safe because we are processing a message targeting this thread.
354     let result = unsafe { handle_window_message(window_state, hwnd, message) }
355         .with_context(|| format_err!("handle the window message: {:?}", message));
356 
357     match result {
358         Ok(result) => result,
359         Err(err) => {
360             error!("{:?}", err);
361             // SAFETY: Safe because we are processing a message targeting this thread.
362             unsafe { DefWindowProcW(hwnd, msg, w_param, l_param) }
363         }
364     }
365 }
366 
367 static WND_CLASS_REGISTRATION_SUCCESS: Mutex<bool> = Mutex::new(false);
368 
369 /// # Safety
370 ///  - The passed in `worker` must not be destroyed before the created window is destroyed if the
371 ///    window creation succeeds.
372 ///  - The WNDPROC must be called within the same thread that calls create_window.
373 /// # Arguments
374 /// * `worker` - we use the runtime borrow checker to make sure there is no unwanted borrowing to
375 ///   the underlying worker.
376 #[deny(unsafe_op_in_unsafe_fn)]
create_window<AppState, AppStateBuilder>( parent: HWND, initial_window_size: &Size2D<i32, UnknownUnit>, app_state_builder: AppStateBuilder, window_state: &RefCell<Option<WindowState<AppState>>>, user_event_rx: Receiver<AppState::UserEvent>, ) -> Result<HWND> where AppState: ApplicationState, AppStateBuilder: ApplicationStateBuilder<Target = AppState>,377 unsafe fn create_window<AppState, AppStateBuilder>(
378     parent: HWND,
379     initial_window_size: &Size2D<i32, UnknownUnit>,
380     app_state_builder: AppStateBuilder,
381     window_state: &RefCell<Option<WindowState<AppState>>>,
382     user_event_rx: Receiver<AppState::UserEvent>,
383 ) -> Result<HWND>
384 where
385     AppState: ApplicationState,
386     AppStateBuilder: ApplicationStateBuilder<Target = AppState>,
387 {
388     // SAFETY: Safe because we pass a null pointer for the module which tells this function to
389     // return the current executable name.
390     let hmodule = unsafe { GetModuleHandleW(null_mut()) };
391     if hmodule.is_null() {
392         syscall_bail!("Failed to call GetModuleHandleW() for the current module.");
393     }
394 
395     let class_name = "vulkan-subWin";
396     let class_name_win32_str = win32_wide_string(class_name);
397     let window_class = WNDCLASSEXW {
398         cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
399         style: CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
400         lpfnWndProc: Some(wnd_proc::<AppState>),
401         cbClsExtra: 0,
402         cbWndExtra: 0,
403         hInstance: hmodule,
404         hIcon: null_mut(),
405         hCursor: null_mut(),
406         hbrBackground: null_mut(),
407         lpszMenuName: null_mut(),
408         lpszClassName: class_name_win32_str.as_ptr(),
409         hIconSm: null_mut(),
410     };
411 
412     {
413         let mut wnd_class_registration_success = WND_CLASS_REGISTRATION_SUCCESS.lock();
414         if !*wnd_class_registration_success {
415             // Check if a window class with the same name already exists. This is unexpected.
416             {
417                 let mut window_class_info = MaybeUninit::uninit();
418                 // SAFETY: Safe because we pass valid pointers.
419                 if unsafe {
420                     GetClassInfoExW(
421                         window_class.hInstance,
422                         window_class.lpszClassName,
423                         window_class_info.as_mut_ptr(),
424                     )
425                 } != 0
426                 {
427                     bail!(
428                         "A window class with the same name {} has already been registered.",
429                         class_name
430                     );
431                 } else {
432                     // SAFETY: trivially safe
433                     let sys_error = unsafe { GetLastError() };
434                     if sys_error != ERROR_CLASS_DOES_NOT_EXIST {
435                         bail!("Failed to call GetClassInfoExW: {}", sys_error);
436                     }
437                 }
438             }
439             // SAFETY: Safe because we know the lifetime of `window_class`, and we handle failures
440             // below.
441             if unsafe { RegisterClassExW(&window_class) } == 0 {
442                 syscall_bail!("Failed to call RegisterClassExW()");
443             }
444             *wnd_class_registration_success = true;
445         }
446     }
447 
448     let window_name = win32_wide_string("sub");
449     let mut style = WS_DISABLED | WS_VISIBLE;
450     // In normal practice parent will not be NULL, but it is convenient for this function to also
451     // support a NULL parent for unit tests.
452     if !parent.is_null() {
453         style |= WS_CHILD;
454     }
455     // SAFETY: Safe because we handle failures below.
456     let hwnd = unsafe {
457         CreateWindowExW(
458             WS_EX_NOPARENTNOTIFY,
459             class_name_win32_str.as_ptr(),
460             window_name.as_ptr(),
461             style,
462             0,
463             0,
464             initial_window_size.width,
465             initial_window_size.height,
466             parent,
467             null_mut(),
468             hmodule,
469             window_state as *const _ as LPVOID,
470         )
471     };
472     if hwnd.is_null() {
473         syscall_bail!("Failed to call CreateWindowExW()");
474     }
475     info!("Child window created. HWND = {:#x}", hwnd as usize);
476 
477     // SAFETY: Safe because hwnd is a valid HWND handle, and we won't destroy the window outside
478     // this struct.
479     let window = Arc::new(unsafe { Window::new(hwnd, hmodule) });
480     let app_state = app_state_builder
481         .build(Arc::clone(&window))
482         .context("create the application state")?;
483     *window_state.borrow_mut() = Some(WindowState {
484         app_state,
485         user_event_rx,
486         window,
487     });
488 
489     Ok(hwnd)
490 }
491 
492 pub struct WindowsWindowEventLoop<AppState: ApplicationState> {
493     hwnd: HWND,
494     user_event_tx: SyncSender<AppState::UserEvent>,
495     event_loop_thread: Option<thread::JoinHandle<()>>,
496 }
497 
498 // SAFETY: Safe because HWND handle can be used from multiple threads.
499 unsafe impl<T: ApplicationState> Send for WindowsWindowEventLoop<T> {}
500 
501 impl<AppState: ApplicationState> WindowEventLoop<AppState> for WindowsWindowEventLoop<AppState> {
502     type WindowType = Window;
503 
504     /// # Safety
505     /// The parent window must outlive the lifetime of this object.
506     #[deny(unsafe_op_in_unsafe_fn)]
create<Builder>( parent: NativeWindowType, initial_window_size: &Size2D<i32, UnknownUnit>, application_state_builder: Builder, ) -> Result<Self> where Builder: ApplicationStateBuilder<Target = AppState>,507     unsafe fn create<Builder>(
508         parent: NativeWindowType,
509         initial_window_size: &Size2D<i32, UnknownUnit>,
510         application_state_builder: Builder,
511     ) -> Result<Self>
512     where
513         Builder: ApplicationStateBuilder<Target = AppState>,
514     {
515         let parent = parent as isize;
516         let initial_window_size = *initial_window_size;
517         let (tx, rx) = channel();
518         // The only user events we have are Post and GetVulkanDevice. There's no point in queueing
519         // more Post commands than there are swapchain images (usually 3), and GetVulkanDevice is
520         // only used at initialization. Thus, a reasonable channel size is 5, and if any more
521         // events are queued then it will block the caller.
522         let (user_event_tx, user_event_rx) = sync_channel(5);
523         let event_loop_thread = thread::Builder::new()
524             .name("subwin event loop thread".to_owned())
525             .spawn(move || {
526                 let window_state = RefCell::new(None);
527                 // SAFETY: Safe because worker will be destroyed at the end of the thread, and the
528                 // message pump would have already stopped then. And we are
529                 // processing the message in the same thread.
530                 let create_window_result = unsafe {
531                     create_window(
532                         parent as HWND,
533                         &initial_window_size,
534                         application_state_builder,
535                         &window_state,
536                         user_event_rx,
537                     )
538                 }
539                 .context("Failed to create the window.");
540                 let hwnd = match create_window_result {
541                     Ok(hwnd) => hwnd,
542                     Err(err) => {
543                         tx.send(Err(err)).expect(
544                             "Failed to send the create window message back to the caller thread",
545                         );
546                         return;
547                     }
548                 };
549 
550                 tx.send(Ok(hwnd as isize))
551                     .expect("send the HWND back to the caller thread");
552                 loop {
553                     let mut message = MaybeUninit::uninit();
554                     // SAFETY: Safe because we handle the error case.
555                     match unsafe { GetMessageW(message.as_mut_ptr(), null_mut(), 0, 0) } {
556                         // Receive WM_QUIT
557                         0 => break,
558                         -1 => {
559                             // SAFETY: trivially safe
560                             error!("GetMessage fails with error code {}", unsafe {
561                                 GetLastError()
562                             });
563                         }
564                         _ => {
565                             // SAFETY: Safe because GetMessage returns with success, and GetMessage
566                             // should fill message on success.
567                             let message = unsafe { message.assume_init() };
568                             // SAFETY: Safe because we are calling this function on the thread where
569                             // the window is created.
570                             unsafe { DispatchMessageW(&message) };
571                         }
572                     }
573                 }
574             })
575             .context("create the worker thread")?;
576         let hwnd = rx
577             .recv()
578             .context("receive the HWND from the worker thread")??;
579         Ok(Self {
580             hwnd: hwnd as HWND,
581             user_event_tx,
582             event_loop_thread: Some(event_loop_thread),
583         })
584     }
585 
move_window(&self, pos: &Box2D<i32, UnknownUnit>) -> Result<()>586     fn move_window(&self, pos: &Box2D<i32, UnknownUnit>) -> Result<()> {
587         // SAFETY: Safe because we handle the error.
588         if unsafe {
589             MoveWindow(
590                 self.hwnd,
591                 pos.min.x,
592                 pos.min.y,
593                 pos.width(),
594                 pos.height(),
595                 TRUE,
596             )
597         } == 0
598         {
599             syscall_bail!("Failed to call MoveWindow");
600         }
601         Ok(())
602     }
603 
send_event(&self, event: AppState::UserEvent) -> Result<()>604     fn send_event(&self, event: AppState::UserEvent) -> Result<()> {
605         self.user_event_tx.send(event).map_err(|e| {
606             format_err!("Failed to send post command to the worker thread: {:?}", e)
607         })?;
608         // SAFETY: Safe because arguments outlive function call and contain no pointers.
609         if unsafe { PostMessageW(self.hwnd, WM_USER_USER_EVENT_AVAILABLE, 0, 0) } == 0 {
610             syscall_bail!(
611                 "Failed to call PostMessage to send the notification to the worker thread"
612             );
613         }
614         Ok(())
615     }
616 }
617 
618 impl<AppState: ApplicationState> Drop for WindowsWindowEventLoop<AppState> {
drop(&mut self)619     fn drop(&mut self) {
620         // SAFETY: Safe because we handle the error.
621         if unsafe { PostMessageW(self.hwnd, WM_CLOSE, 0, 0) } == 0 {
622             // SAFETY: trivially safe
623             let error = unsafe { GetLastError() };
624             if error != ERROR_INVALID_WINDOW_HANDLE {
625                 error!(
626                     "Failed to post the WM_CLOSE message the window. (Error code {})",
627                     error
628                 );
629             } else {
630                 info!(concat!(
631                     "Failed to post the WM_CLOSE message the window with ",
632                     "ERROR_INVALID_WINDOW_HANDLE. This is benign if the window is already closed ",
633                     "through other mechanisms."
634                 ));
635             }
636         }
637         if let Some(worker_thread) = self.event_loop_thread.take() {
638             // It's Ok to panic on join failure, because it only happens if the worker thread
639             // panics, on which case the whole process should have abort because crosvm sets abort
640             // on panic.
641             worker_thread
642                 .join()
643                 .expect("The worker thread panic unexpectedly");
644         }
645     }
646 }
647 
create_post_image_external_memory_handle_types() -> ExternalMemoryHandleTypes648 pub(crate) fn create_post_image_external_memory_handle_types() -> ExternalMemoryHandleTypes {
649     ExternalMemoryHandleTypes {
650         opaque_win32: true,
651         ..ExternalMemoryHandleTypes::empty()
652     }
653 }
654 
655 // The ownership of the descriptor is transferred to the returned MemoryImportInfo.
create_post_image_memory_import_info( memory_descriptor: &dyn AsRawDescriptor, ) -> MemoryImportInfo656 pub(crate) fn create_post_image_memory_import_info(
657     memory_descriptor: &dyn AsRawDescriptor,
658 ) -> MemoryImportInfo {
659     MemoryImportInfo::Win32 {
660         handle_type: ExternalMemoryHandleType::OpaqueWin32,
661         handle: memory_descriptor.as_raw_descriptor(),
662     }
663 }
664 
import_semaphore_from_descriptor( device: &Arc<Device>, semaphore: vk::Semaphore, descriptor: &dyn AsRawDescriptor, ) -> vk::Result665 pub(crate) fn import_semaphore_from_descriptor(
666     device: &Arc<Device>,
667     semaphore: vk::Semaphore,
668     descriptor: &dyn AsRawDescriptor,
669 ) -> vk::Result {
670     let import_handle_info = vk::ImportSemaphoreWin32HandleInfoKHR::builder()
671         .semaphore(semaphore)
672         .flags(vk::SemaphoreImportFlags::empty())
673         .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_WIN32)
674         .handle(descriptor.as_raw_descriptor())
675         .name(null())
676         .build();
677     // SAFETY: Safe because `import_handle_info` outlives call to import_semaphore_win32_handle_khr
678     // and because we know `import_semaphore_win32_handle_khr` will be non-null on windows.
679     unsafe {
680         (device
681             .fns()
682             .khr_external_semaphore_win32
683             .import_semaphore_win32_handle_khr)(
684             device.internal_object(), &import_handle_info
685         )
686     }
687 }
688 
689 #[cfg(test)]
690 mod tests {
691     use std::any::Any;
692     use std::io;
693     use std::sync::atomic::AtomicBool;
694 
695     use winapi::um::winuser::SetWindowTextW;
696 
697     use super::*;
698 
699     #[test]
user_event_handler_can_call_into_wndproc()700     fn user_event_handler_can_call_into_wndproc() {
701         static PROCESS_EVENT_CALLED: AtomicBool = AtomicBool::new(false);
702 
703         struct UserEvent;
704         struct State {
705             hwnd: HWND,
706         }
707         impl ApplicationState for State {
708             type UserEvent = UserEvent;
709 
710             fn process_event(&self, _: WindowEvent<Self::UserEvent>) {
711                 // SAFETY: Safe because "test" string literal is static.
712                 let res = unsafe { SetWindowTextW(self.hwnd, win32_wide_string("test").as_ptr()) };
713                 assert!(
714                     res != 0,
715                     "SetWindowTextW failed: {:?}",
716                     io::Error::last_os_error()
717                 );
718                 PROCESS_EVENT_CALLED.store(true, std::sync::atomic::Ordering::SeqCst);
719             }
720         }
721         struct StateBuilder;
722         impl ApplicationStateBuilder for StateBuilder {
723             type Target = State;
724 
725             fn build<T: WindowT>(self, window: Arc<T>) -> Result<Self::Target> {
726                 let window =
727                     Arc::downcast::<Window>(window as Arc<dyn Any + Sync + Send + 'static>)
728                         .expect("Failed to downcast the window type");
729                 Ok(State {
730                     hwnd: window.hwnd as HWND,
731                 })
732             }
733         }
734         let event_loop =
735             // SAFETY: safe because 0 for parent hwnd means this is a toplevel window so there is
736             // no parent window that needs to outlive this object.
737             unsafe { WindowsWindowEventLoop::create(0 as HWND, &size2(640, 480), StateBuilder) }
738                 .unwrap_or_else(|e| panic!("Failed to create the window event loop: {:?}", e));
739         event_loop
740             .send_event(UserEvent)
741             .unwrap_or_else(|e| panic!("Failed to send the user event: {:?}", e));
742 
743         let max_timeout = Duration::from_secs(5);
744         let poll_interval = Duration::from_millis(100);
745         let loop_start = std::time::Instant::now();
746 
747         while !PROCESS_EVENT_CALLED.load(std::sync::atomic::Ordering::SeqCst) {
748             if loop_start.elapsed() > max_timeout {
749                 panic!("Timeout reached waiting for process_event_to be called");
750             }
751             std::thread::sleep(poll_interval);
752         }
753     }
754 }
755