1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker #![cfg_attr(unix, allow(dead_code))] 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use std::cell::RefCell; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::HashMap; 9*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc::channel; 10*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc::Receiver; 11*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc::RecvTimeoutError; 12*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc::Sender; 13*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc; 14*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration; 15*bb4ee6a4SAndroid Build Coastguard Worker 16*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow; 17*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::ensure; 18*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::format_err; 19*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context; 20*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result; 21*bb4ee6a4SAndroid Build Coastguard Worker use ash::vk::UUID_SIZE; 22*bb4ee6a4SAndroid Build Coastguard Worker use ash::vk::{self}; 23*bb4ee6a4SAndroid Build Coastguard Worker use base::error; 24*bb4ee6a4SAndroid Build Coastguard Worker use base::warn; 25*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor; 26*bb4ee6a4SAndroid Build Coastguard Worker use euclid::Box2D; 27*bb4ee6a4SAndroid Build Coastguard Worker use euclid::Size2D; 28*bb4ee6a4SAndroid Build Coastguard Worker use euclid::UnknownUnit; 29*bb4ee6a4SAndroid Build Coastguard Worker use smallvec::SmallVec; 30*bb4ee6a4SAndroid Build Coastguard Worker 31*bb4ee6a4SAndroid Build Coastguard Worker mod external_image; 32*bb4ee6a4SAndroid Build Coastguard Worker mod post_worker; 33*bb4ee6a4SAndroid Build Coastguard Worker mod sys; 34*bb4ee6a4SAndroid Build Coastguard Worker 35*bb4ee6a4SAndroid Build Coastguard Worker pub use external_image::AcquireImageMemoryBarrier; 36*bb4ee6a4SAndroid Build Coastguard Worker pub use external_image::ExternalImage; 37*bb4ee6a4SAndroid Build Coastguard Worker pub use external_image::ExternalImageAccess; 38*bb4ee6a4SAndroid Build Coastguard Worker pub use external_image::ReleaseImageMemoryBarrier; 39*bb4ee6a4SAndroid Build Coastguard Worker use post_worker::PostWorker; 40*bb4ee6a4SAndroid Build Coastguard Worker use post_worker::Timepoint; 41*bb4ee6a4SAndroid Build Coastguard Worker use sync::create_promise_and_waitable; 42*bb4ee6a4SAndroid Build Coastguard Worker use sync::Promise; 43*bb4ee6a4SAndroid Build Coastguard Worker use sync::Waitable; 44*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::device::Device; 45*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::image::sys::UnsafeImageCreateInfo; 46*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::image::ImageCreateFlags; 47*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::image::ImageDimensions; 48*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::image::ImageLayout; 49*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::image::ImageUsage; 50*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::memory::ExternalMemoryHandleTypes; 51*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::memory::MemoryAllocateInfo; 52*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::sync::ExternalSemaphoreHandleTypes; 53*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::sync::Semaphore; 54*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::sync::SemaphoreCreateInfo; 55*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::sync::Sharing; 56*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::VulkanLibrary; 57*bb4ee6a4SAndroid Build Coastguard Worker use vulkano::VulkanObject; 58*bb4ee6a4SAndroid Build Coastguard Worker 59*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::platform::create_post_image_external_memory_handle_types; 60*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::platform::create_post_image_memory_import_info; 61*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::platform::import_semaphore_from_descriptor; 62*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::platform::NativeWindowType; 63*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::ApplicationState; 64*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::ApplicationStateBuilder; 65*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use self::sys::PlatformWindowEventLoop; 66*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::Window; 67*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::WindowEvent; 68*bb4ee6a4SAndroid Build Coastguard Worker use self::sys::WindowEventLoop; 69*bb4ee6a4SAndroid Build Coastguard Worker use crate::SemaphoreTimepoint; 70*bb4ee6a4SAndroid Build Coastguard Worker use crate::VulkanDisplayImageImportMetadata; 71*bb4ee6a4SAndroid Build Coastguard Worker 72*bb4ee6a4SAndroid Build Coastguard Worker /// Vulkan Safety Notes: 73*bb4ee6a4SAndroid Build Coastguard Worker /// Most vulkan APIs are unsafe, but even the wrapper APIs like ash and vulkano will mark their 74*bb4ee6a4SAndroid Build Coastguard Worker /// APIs as unsafe when they cannot ensure that they are 100% obeying the vulkan spec. For the 75*bb4ee6a4SAndroid Build Coastguard Worker /// purposes of VulkanDisplay, however, we do not consider disobeying the vulkan spec to be unsafe 76*bb4ee6a4SAndroid Build Coastguard Worker /// in terms of memory safety. Safety comments in these cases will say: 77*bb4ee6a4SAndroid Build Coastguard Worker /// "Safe irrespective of vulkan spec conformance" 78*bb4ee6a4SAndroid Build Coastguard Worker /// 79*bb4ee6a4SAndroid Build Coastguard Worker /// If the function is unsafe for any other reason we will still note why it's safe. 80*bb4ee6a4SAndroid Build Coastguard Worker 81*bb4ee6a4SAndroid Build Coastguard Worker pub type SemaphoreId = u32; 82*bb4ee6a4SAndroid Build Coastguard Worker pub type ImageId = u32; 83*bb4ee6a4SAndroid Build Coastguard Worker 84*bb4ee6a4SAndroid Build Coastguard Worker pub enum UserEvent { 85*bb4ee6a4SAndroid Build Coastguard Worker GetVulkanDevice(Sender<Arc<Device>>), 86*bb4ee6a4SAndroid Build Coastguard Worker PostCommand { 87*bb4ee6a4SAndroid Build Coastguard Worker image: ExternalImage, 88*bb4ee6a4SAndroid Build Coastguard Worker last_layout_transition: (ImageLayout, ImageLayout), 89*bb4ee6a4SAndroid Build Coastguard Worker acquire_timepoint: Option<Timepoint>, 90*bb4ee6a4SAndroid Build Coastguard Worker release_timepoint: Timepoint, 91*bb4ee6a4SAndroid Build Coastguard Worker image_return: Sender<ExternalImage>, 92*bb4ee6a4SAndroid Build Coastguard Worker promise: Promise, 93*bb4ee6a4SAndroid Build Coastguard Worker }, 94*bb4ee6a4SAndroid Build Coastguard Worker } 95*bb4ee6a4SAndroid Build Coastguard Worker 96*bb4ee6a4SAndroid Build Coastguard Worker pub struct VulkanState { 97*bb4ee6a4SAndroid Build Coastguard Worker // Post worker submits renders and posts to vulkan. It needs to be in a RefCell because 98*bb4ee6a4SAndroid Build Coastguard Worker // process_event cannot take a mutable reference to ApplicationState. 99*bb4ee6a4SAndroid Build Coastguard Worker post_worker: RefCell<PostWorker>, 100*bb4ee6a4SAndroid Build Coastguard Worker } 101*bb4ee6a4SAndroid Build Coastguard Worker 102*bb4ee6a4SAndroid Build Coastguard Worker impl ApplicationState for VulkanState { 103*bb4ee6a4SAndroid Build Coastguard Worker type UserEvent = UserEvent; 104*bb4ee6a4SAndroid Build Coastguard Worker 105*bb4ee6a4SAndroid Build Coastguard Worker /// Process events coming from the Window. process_event(&self, event: WindowEvent<Self::UserEvent>)106*bb4ee6a4SAndroid Build Coastguard Worker fn process_event(&self, event: WindowEvent<Self::UserEvent>) { 107*bb4ee6a4SAndroid Build Coastguard Worker match event { 108*bb4ee6a4SAndroid Build Coastguard Worker WindowEvent::User(UserEvent::GetVulkanDevice(sender)) => { 109*bb4ee6a4SAndroid Build Coastguard Worker sender 110*bb4ee6a4SAndroid Build Coastguard Worker .send(self.post_worker.borrow().device()) 111*bb4ee6a4SAndroid Build Coastguard Worker .expect("Should send VkDevice back to the caller successfully."); 112*bb4ee6a4SAndroid Build Coastguard Worker } 113*bb4ee6a4SAndroid Build Coastguard Worker WindowEvent::User(UserEvent::PostCommand { 114*bb4ee6a4SAndroid Build Coastguard Worker image, 115*bb4ee6a4SAndroid Build Coastguard Worker last_layout_transition, 116*bb4ee6a4SAndroid Build Coastguard Worker acquire_timepoint, 117*bb4ee6a4SAndroid Build Coastguard Worker release_timepoint, 118*bb4ee6a4SAndroid Build Coastguard Worker image_return, 119*bb4ee6a4SAndroid Build Coastguard Worker promise, 120*bb4ee6a4SAndroid Build Coastguard Worker }) => { 121*bb4ee6a4SAndroid Build Coastguard Worker // If this post triggers a resize event then the recursive wndproc call will 122*bb4ee6a4SAndroid Build Coastguard Worker // call into this function again and trigger another borrow which will panic. 123*bb4ee6a4SAndroid Build Coastguard Worker // TODO (b/314379499): figure out a way to avoid this 124*bb4ee6a4SAndroid Build Coastguard Worker let image = self.post_worker.borrow_mut().post( 125*bb4ee6a4SAndroid Build Coastguard Worker image, 126*bb4ee6a4SAndroid Build Coastguard Worker last_layout_transition, 127*bb4ee6a4SAndroid Build Coastguard Worker acquire_timepoint, 128*bb4ee6a4SAndroid Build Coastguard Worker release_timepoint, 129*bb4ee6a4SAndroid Build Coastguard Worker ); 130*bb4ee6a4SAndroid Build Coastguard Worker promise.signal(); 131*bb4ee6a4SAndroid Build Coastguard Worker image_return 132*bb4ee6a4SAndroid Build Coastguard Worker .send(image) 133*bb4ee6a4SAndroid Build Coastguard Worker .expect("Should send ExternalImage back to the caller successfully."); 134*bb4ee6a4SAndroid Build Coastguard Worker } 135*bb4ee6a4SAndroid Build Coastguard Worker WindowEvent::Resized => { 136*bb4ee6a4SAndroid Build Coastguard Worker // If this resize event triggers another resize event then this will fail. 137*bb4ee6a4SAndroid Build Coastguard Worker // TODO (b/314379499): figure out a way to avoid this 138*bb4ee6a4SAndroid Build Coastguard Worker if let Err(err) = self.post_worker.borrow_mut().recreate_swapchain() { 139*bb4ee6a4SAndroid Build Coastguard Worker panic!( 140*bb4ee6a4SAndroid Build Coastguard Worker concat!( 141*bb4ee6a4SAndroid Build Coastguard Worker "Failed to recreate the swapchain when handling the Resized window ", 142*bb4ee6a4SAndroid Build Coastguard Worker "event: {:?}." 143*bb4ee6a4SAndroid Build Coastguard Worker ), 144*bb4ee6a4SAndroid Build Coastguard Worker err 145*bb4ee6a4SAndroid Build Coastguard Worker ); 146*bb4ee6a4SAndroid Build Coastguard Worker } 147*bb4ee6a4SAndroid Build Coastguard Worker } 148*bb4ee6a4SAndroid Build Coastguard Worker } 149*bb4ee6a4SAndroid Build Coastguard Worker } 150*bb4ee6a4SAndroid Build Coastguard Worker } 151*bb4ee6a4SAndroid Build Coastguard Worker 152*bb4ee6a4SAndroid Build Coastguard Worker struct VulkanStateBuilder { 153*bb4ee6a4SAndroid Build Coastguard Worker vulkan_library: Arc<VulkanLibrary>, 154*bb4ee6a4SAndroid Build Coastguard Worker device_uuid: [u8; vk::UUID_SIZE], 155*bb4ee6a4SAndroid Build Coastguard Worker driver_uuid: [u8; vk::UUID_SIZE], 156*bb4ee6a4SAndroid Build Coastguard Worker } 157*bb4ee6a4SAndroid Build Coastguard Worker 158*bb4ee6a4SAndroid Build Coastguard Worker impl ApplicationStateBuilder for VulkanStateBuilder { 159*bb4ee6a4SAndroid Build Coastguard Worker type Target = VulkanState; 160*bb4ee6a4SAndroid Build Coastguard Worker build<T: Window>(self, window: Arc<T>) -> Result<VulkanState>161*bb4ee6a4SAndroid Build Coastguard Worker fn build<T: Window>(self, window: Arc<T>) -> Result<VulkanState> { 162*bb4ee6a4SAndroid Build Coastguard Worker let post_worker = PostWorker::new( 163*bb4ee6a4SAndroid Build Coastguard Worker self.vulkan_library, 164*bb4ee6a4SAndroid Build Coastguard Worker &self.device_uuid, 165*bb4ee6a4SAndroid Build Coastguard Worker &self.driver_uuid, 166*bb4ee6a4SAndroid Build Coastguard Worker Arc::clone(&window) as _, 167*bb4ee6a4SAndroid Build Coastguard Worker ) 168*bb4ee6a4SAndroid Build Coastguard Worker .context("creating the post worker")?; 169*bb4ee6a4SAndroid Build Coastguard Worker Ok(VulkanState { 170*bb4ee6a4SAndroid Build Coastguard Worker post_worker: RefCell::new(post_worker), 171*bb4ee6a4SAndroid Build Coastguard Worker }) 172*bb4ee6a4SAndroid Build Coastguard Worker } 173*bb4ee6a4SAndroid Build Coastguard Worker } 174*bb4ee6a4SAndroid Build Coastguard Worker 175*bb4ee6a4SAndroid Build Coastguard Worker pub struct VulkanDisplayImpl<T: WindowEventLoop<VulkanState>> { 176*bb4ee6a4SAndroid Build Coastguard Worker ash_device: ash::Device, 177*bb4ee6a4SAndroid Build Coastguard Worker device: Arc<Device>, 178*bb4ee6a4SAndroid Build Coastguard Worker window_event_loop: T, 179*bb4ee6a4SAndroid Build Coastguard Worker imported_semaphores: HashMap<SemaphoreId, Arc<Semaphore>>, 180*bb4ee6a4SAndroid Build Coastguard Worker imported_images: HashMap<ImageId, ExternalImage>, 181*bb4ee6a4SAndroid Build Coastguard Worker used_image_receivers: HashMap<ImageId, Receiver<ExternalImage>>, 182*bb4ee6a4SAndroid Build Coastguard Worker } 183*bb4ee6a4SAndroid Build Coastguard Worker 184*bb4ee6a4SAndroid Build Coastguard Worker impl<T: WindowEventLoop<VulkanState>> VulkanDisplayImpl<T> { 185*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety 186*bb4ee6a4SAndroid Build Coastguard Worker /// The parent window must outlive the lifetime of this object. 187*bb4ee6a4SAndroid Build Coastguard Worker #[deny(unsafe_op_in_unsafe_fn)] new( vulkan_library: Arc<VulkanLibrary>, parent: NativeWindowType, initial_window_size: &Size2D<i32, UnknownUnit>, device_uuid: [u8; UUID_SIZE], driver_uuid: [u8; UUID_SIZE], ) -> Result<Self>188*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn new( 189*bb4ee6a4SAndroid Build Coastguard Worker vulkan_library: Arc<VulkanLibrary>, 190*bb4ee6a4SAndroid Build Coastguard Worker parent: NativeWindowType, 191*bb4ee6a4SAndroid Build Coastguard Worker initial_window_size: &Size2D<i32, UnknownUnit>, 192*bb4ee6a4SAndroid Build Coastguard Worker device_uuid: [u8; UUID_SIZE], 193*bb4ee6a4SAndroid Build Coastguard Worker driver_uuid: [u8; UUID_SIZE], 194*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Self> { 195*bb4ee6a4SAndroid Build Coastguard Worker let vulkan_state_builder = VulkanStateBuilder { 196*bb4ee6a4SAndroid Build Coastguard Worker vulkan_library, 197*bb4ee6a4SAndroid Build Coastguard Worker device_uuid, 198*bb4ee6a4SAndroid Build Coastguard Worker driver_uuid, 199*bb4ee6a4SAndroid Build Coastguard Worker }; 200*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: Safe because it is guaranteed by the safety requirement of this function that 201*bb4ee6a4SAndroid Build Coastguard Worker // the parent window outlives the event loop object. 202*bb4ee6a4SAndroid Build Coastguard Worker let window_event_loop = unsafe { 203*bb4ee6a4SAndroid Build Coastguard Worker T::create(parent, initial_window_size, vulkan_state_builder) 204*bb4ee6a4SAndroid Build Coastguard Worker .context("create window and event loop")? 205*bb4ee6a4SAndroid Build Coastguard Worker }; 206*bb4ee6a4SAndroid Build Coastguard Worker let (vk_device_tx, vk_device_rx) = channel(); 207*bb4ee6a4SAndroid Build Coastguard Worker window_event_loop 208*bb4ee6a4SAndroid Build Coastguard Worker .send_event(UserEvent::GetVulkanDevice(vk_device_tx)) 209*bb4ee6a4SAndroid Build Coastguard Worker .context("retrieve VkDevice from the window event loop")?; 210*bb4ee6a4SAndroid Build Coastguard Worker let device = loop { 211*bb4ee6a4SAndroid Build Coastguard Worker const TIMEOUT: Duration = Duration::from_secs(60); 212*bb4ee6a4SAndroid Build Coastguard Worker match vk_device_rx.recv_timeout(TIMEOUT) { 213*bb4ee6a4SAndroid Build Coastguard Worker Ok(value) => break value, 214*bb4ee6a4SAndroid Build Coastguard Worker 215*bb4ee6a4SAndroid Build Coastguard Worker Err(RecvTimeoutError::Timeout) => { 216*bb4ee6a4SAndroid Build Coastguard Worker warn!( 217*bb4ee6a4SAndroid Build Coastguard Worker "Didn't receive the VkDevice from the event loop for {:?}. Retry.", 218*bb4ee6a4SAndroid Build Coastguard Worker TIMEOUT 219*bb4ee6a4SAndroid Build Coastguard Worker ); 220*bb4ee6a4SAndroid Build Coastguard Worker continue; 221*bb4ee6a4SAndroid Build Coastguard Worker } 222*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => { 223*bb4ee6a4SAndroid Build Coastguard Worker return Err(format_err!( 224*bb4ee6a4SAndroid Build Coastguard Worker "Failed to receive VkDevice from the event loop: {:?}.", 225*bb4ee6a4SAndroid Build Coastguard Worker e 226*bb4ee6a4SAndroid Build Coastguard Worker )); 227*bb4ee6a4SAndroid Build Coastguard Worker } 228*bb4ee6a4SAndroid Build Coastguard Worker } 229*bb4ee6a4SAndroid Build Coastguard Worker }; 230*bb4ee6a4SAndroid Build Coastguard Worker let ash_device = 231*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: Safe because we trust the vulkan device we get from the window event loop and 232*bb4ee6a4SAndroid Build Coastguard Worker // the instance_fn comes from an instance we know is valid because the device was created 233*bb4ee6a4SAndroid Build Coastguard Worker // with it. 234*bb4ee6a4SAndroid Build Coastguard Worker unsafe { ash::Device::load(&device.instance().fns().v1_0, device.internal_object()) }; 235*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self { 236*bb4ee6a4SAndroid Build Coastguard Worker ash_device, 237*bb4ee6a4SAndroid Build Coastguard Worker device, 238*bb4ee6a4SAndroid Build Coastguard Worker window_event_loop, 239*bb4ee6a4SAndroid Build Coastguard Worker imported_semaphores: Default::default(), 240*bb4ee6a4SAndroid Build Coastguard Worker imported_images: Default::default(), 241*bb4ee6a4SAndroid Build Coastguard Worker used_image_receivers: Default::default(), 242*bb4ee6a4SAndroid Build Coastguard Worker }) 243*bb4ee6a4SAndroid Build Coastguard Worker } 244*bb4ee6a4SAndroid Build Coastguard Worker move_window(&self, pos: &Box2D<i32, UnknownUnit>) -> Result<()>245*bb4ee6a4SAndroid Build Coastguard Worker pub fn move_window(&self, pos: &Box2D<i32, UnknownUnit>) -> Result<()> { 246*bb4ee6a4SAndroid Build Coastguard Worker self.window_event_loop.move_window(pos) 247*bb4ee6a4SAndroid Build Coastguard Worker } 248*bb4ee6a4SAndroid Build Coastguard Worker import_semaphore( &mut self, semaphore_id: SemaphoreId, descriptor: &dyn AsRawDescriptor, ) -> Result<()>249*bb4ee6a4SAndroid Build Coastguard Worker pub fn import_semaphore( 250*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 251*bb4ee6a4SAndroid Build Coastguard Worker semaphore_id: SemaphoreId, 252*bb4ee6a4SAndroid Build Coastguard Worker descriptor: &dyn AsRawDescriptor, 253*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 254*bb4ee6a4SAndroid Build Coastguard Worker let mut type_create_info = vk::SemaphoreTypeCreateInfo::builder() 255*bb4ee6a4SAndroid Build Coastguard Worker .semaphore_type(vk::SemaphoreType::TIMELINE) 256*bb4ee6a4SAndroid Build Coastguard Worker .initial_value(0) 257*bb4ee6a4SAndroid Build Coastguard Worker .build(); 258*bb4ee6a4SAndroid Build Coastguard Worker let create_info = vk::SemaphoreCreateInfo::builder() 259*bb4ee6a4SAndroid Build Coastguard Worker .push_next(&mut type_create_info) 260*bb4ee6a4SAndroid Build Coastguard Worker .build(); 261*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: Safe because create_info and it's fields are local to this function and outlive 262*bb4ee6a4SAndroid Build Coastguard Worker // this function call. 263*bb4ee6a4SAndroid Build Coastguard Worker let semaphore = unsafe { self.ash_device.create_semaphore(&create_info, None) } 264*bb4ee6a4SAndroid Build Coastguard Worker .context("create timeline semaphore")?; 265*bb4ee6a4SAndroid Build Coastguard Worker 266*bb4ee6a4SAndroid Build Coastguard Worker let res = import_semaphore_from_descriptor(&self.device, semaphore, descriptor); 267*bb4ee6a4SAndroid Build Coastguard Worker ensure!( 268*bb4ee6a4SAndroid Build Coastguard Worker res == vk::Result::SUCCESS, 269*bb4ee6a4SAndroid Build Coastguard Worker "Failed to import the external handle to the semaphore: {}.", 270*bb4ee6a4SAndroid Build Coastguard Worker res 271*bb4ee6a4SAndroid Build Coastguard Worker ); 272*bb4ee6a4SAndroid Build Coastguard Worker 273*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: Safe irrespective of vulkan spec conformance 274*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { 275*bb4ee6a4SAndroid Build Coastguard Worker Semaphore::from_handle( 276*bb4ee6a4SAndroid Build Coastguard Worker Arc::clone(&self.device), 277*bb4ee6a4SAndroid Build Coastguard Worker semaphore, 278*bb4ee6a4SAndroid Build Coastguard Worker SemaphoreCreateInfo { 279*bb4ee6a4SAndroid Build Coastguard Worker // Note that as of vulkano version 0.34.1, this 280*bb4ee6a4SAndroid Build Coastguard Worker // export_handle_types field is only used to validate which 281*bb4ee6a4SAndroid Build Coastguard Worker // export APIs can be used in the future. We do not export 282*bb4ee6a4SAndroid Build Coastguard Worker // this semaphore so we do not need to specify any export 283*bb4ee6a4SAndroid Build Coastguard Worker // handle types. 284*bb4ee6a4SAndroid Build Coastguard Worker export_handle_types: ExternalSemaphoreHandleTypes::empty(), 285*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 286*bb4ee6a4SAndroid Build Coastguard Worker }, 287*bb4ee6a4SAndroid Build Coastguard Worker ) 288*bb4ee6a4SAndroid Build Coastguard Worker }; 289*bb4ee6a4SAndroid Build Coastguard Worker 290*bb4ee6a4SAndroid Build Coastguard Worker if self 291*bb4ee6a4SAndroid Build Coastguard Worker .imported_semaphores 292*bb4ee6a4SAndroid Build Coastguard Worker .insert(semaphore_id, Arc::new(res)) 293*bb4ee6a4SAndroid Build Coastguard Worker .is_some() 294*bb4ee6a4SAndroid Build Coastguard Worker { 295*bb4ee6a4SAndroid Build Coastguard Worker warn!("Reused semaphore_id {}", semaphore_id); 296*bb4ee6a4SAndroid Build Coastguard Worker } 297*bb4ee6a4SAndroid Build Coastguard Worker 298*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 299*bb4ee6a4SAndroid Build Coastguard Worker } 300*bb4ee6a4SAndroid Build Coastguard Worker import_image( &mut self, image_id: ImageId, descriptor: &dyn AsRawDescriptor, metadata: VulkanDisplayImageImportMetadata, ) -> Result<()>301*bb4ee6a4SAndroid Build Coastguard Worker pub fn import_image( 302*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 303*bb4ee6a4SAndroid Build Coastguard Worker image_id: ImageId, 304*bb4ee6a4SAndroid Build Coastguard Worker descriptor: &dyn AsRawDescriptor, 305*bb4ee6a4SAndroid Build Coastguard Worker metadata: VulkanDisplayImageImportMetadata, 306*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 307*bb4ee6a4SAndroid Build Coastguard Worker let image_create_flags = metadata.flags; 308*bb4ee6a4SAndroid Build Coastguard Worker let ImageCreateFlags { 309*bb4ee6a4SAndroid Build Coastguard Worker sparse_binding, 310*bb4ee6a4SAndroid Build Coastguard Worker sparse_residency, 311*bb4ee6a4SAndroid Build Coastguard Worker sparse_aliased, 312*bb4ee6a4SAndroid Build Coastguard Worker mutable_format, 313*bb4ee6a4SAndroid Build Coastguard Worker cube_compatible, 314*bb4ee6a4SAndroid Build Coastguard Worker array_2d_compatible, 315*bb4ee6a4SAndroid Build Coastguard Worker block_texel_view_compatible, 316*bb4ee6a4SAndroid Build Coastguard Worker _ne: _, 317*bb4ee6a4SAndroid Build Coastguard Worker } = vk::ImageCreateFlags::from_raw(image_create_flags).into(); 318*bb4ee6a4SAndroid Build Coastguard Worker assert!( 319*bb4ee6a4SAndroid Build Coastguard Worker !(sparse_binding || sparse_residency || sparse_aliased), 320*bb4ee6a4SAndroid Build Coastguard Worker "unsupported image create flags {:#x}", 321*bb4ee6a4SAndroid Build Coastguard Worker image_create_flags 322*bb4ee6a4SAndroid Build Coastguard Worker ); 323*bb4ee6a4SAndroid Build Coastguard Worker let image_type = vk::ImageType::from_raw(metadata.image_type); 324*bb4ee6a4SAndroid Build Coastguard Worker let image_extent = metadata.extent; 325*bb4ee6a4SAndroid Build Coastguard Worker let image_dimensions = match image_type { 326*bb4ee6a4SAndroid Build Coastguard Worker vk::ImageType::TYPE_2D => ImageDimensions::Dim2d { 327*bb4ee6a4SAndroid Build Coastguard Worker width: image_extent.width, 328*bb4ee6a4SAndroid Build Coastguard Worker height: image_extent.height, 329*bb4ee6a4SAndroid Build Coastguard Worker array_layers: metadata.array_layers, 330*bb4ee6a4SAndroid Build Coastguard Worker }, 331*bb4ee6a4SAndroid Build Coastguard Worker _ => unimplemented!(), 332*bb4ee6a4SAndroid Build Coastguard Worker }; 333*bb4ee6a4SAndroid Build Coastguard Worker let format = { 334*bb4ee6a4SAndroid Build Coastguard Worker let format = metadata.format; 335*bb4ee6a4SAndroid Build Coastguard Worker vk::Format::from_raw(format) 336*bb4ee6a4SAndroid Build Coastguard Worker .try_into() 337*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| format_err!("Failed to convert {:#x} to format.", format))? 338*bb4ee6a4SAndroid Build Coastguard Worker }; 339*bb4ee6a4SAndroid Build Coastguard Worker let image_samples = { 340*bb4ee6a4SAndroid Build Coastguard Worker let samples = metadata.samples; 341*bb4ee6a4SAndroid Build Coastguard Worker vk::SampleCountFlags::from_raw(samples) 342*bb4ee6a4SAndroid Build Coastguard Worker .try_into() 343*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| { 344*bb4ee6a4SAndroid Build Coastguard Worker format_err!("Failed to convert {:#x} to sample count flag.", samples) 345*bb4ee6a4SAndroid Build Coastguard Worker })? 346*bb4ee6a4SAndroid Build Coastguard Worker }; 347*bb4ee6a4SAndroid Build Coastguard Worker let image_tiling = { 348*bb4ee6a4SAndroid Build Coastguard Worker let tiling = metadata.tiling; 349*bb4ee6a4SAndroid Build Coastguard Worker vk::ImageTiling::from_raw(tiling) 350*bb4ee6a4SAndroid Build Coastguard Worker .try_into() 351*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| format_err!("Failed to convert {:#x} to image tiling enum.", tiling))? 352*bb4ee6a4SAndroid Build Coastguard Worker }; 353*bb4ee6a4SAndroid Build Coastguard Worker let image_usage = { 354*bb4ee6a4SAndroid Build Coastguard Worker let usage = metadata.usage; 355*bb4ee6a4SAndroid Build Coastguard Worker vk::ImageUsageFlags::from_raw(usage).into() 356*bb4ee6a4SAndroid Build Coastguard Worker }; 357*bb4ee6a4SAndroid Build Coastguard Worker let image_sharing = { 358*bb4ee6a4SAndroid Build Coastguard Worker let sharing_mode = metadata.sharing_mode; 359*bb4ee6a4SAndroid Build Coastguard Worker match vk::SharingMode::from_raw(sharing_mode) { 360*bb4ee6a4SAndroid Build Coastguard Worker vk::SharingMode::EXCLUSIVE => Sharing::Exclusive, 361*bb4ee6a4SAndroid Build Coastguard Worker vk::SharingMode::CONCURRENT => { 362*bb4ee6a4SAndroid Build Coastguard Worker let mut queue_family_indices = SmallVec::new(); 363*bb4ee6a4SAndroid Build Coastguard Worker queue_family_indices.copy_from_slice(&metadata.queue_family_indices); 364*bb4ee6a4SAndroid Build Coastguard Worker Sharing::Concurrent(queue_family_indices) 365*bb4ee6a4SAndroid Build Coastguard Worker } 366*bb4ee6a4SAndroid Build Coastguard Worker _ => return Err(format_err!("Invalid sharing mode {:#x}.", sharing_mode)), 367*bb4ee6a4SAndroid Build Coastguard Worker } 368*bb4ee6a4SAndroid Build Coastguard Worker }; 369*bb4ee6a4SAndroid Build Coastguard Worker let image_initial_layout = { 370*bb4ee6a4SAndroid Build Coastguard Worker let initial_layout = metadata.initial_layout; 371*bb4ee6a4SAndroid Build Coastguard Worker vk::ImageLayout::from_raw(initial_layout) 372*bb4ee6a4SAndroid Build Coastguard Worker .try_into() 373*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| { 374*bb4ee6a4SAndroid Build Coastguard Worker format_err!( 375*bb4ee6a4SAndroid Build Coastguard Worker "Failed to convert the initial layout {:#x} to an image layout.", 376*bb4ee6a4SAndroid Build Coastguard Worker initial_layout 377*bb4ee6a4SAndroid Build Coastguard Worker ) 378*bb4ee6a4SAndroid Build Coastguard Worker })? 379*bb4ee6a4SAndroid Build Coastguard Worker }; 380*bb4ee6a4SAndroid Build Coastguard Worker 381*bb4ee6a4SAndroid Build Coastguard Worker let image = ExternalImage::import( 382*bb4ee6a4SAndroid Build Coastguard Worker &self.device, 383*bb4ee6a4SAndroid Build Coastguard Worker UnsafeImageCreateInfo { 384*bb4ee6a4SAndroid Build Coastguard Worker dimensions: image_dimensions, 385*bb4ee6a4SAndroid Build Coastguard Worker format: Some(format), 386*bb4ee6a4SAndroid Build Coastguard Worker mip_levels: metadata.mip_levels, 387*bb4ee6a4SAndroid Build Coastguard Worker samples: image_samples, 388*bb4ee6a4SAndroid Build Coastguard Worker tiling: image_tiling, 389*bb4ee6a4SAndroid Build Coastguard Worker usage: image_usage, 390*bb4ee6a4SAndroid Build Coastguard Worker stencil_usage: ImageUsage::empty(), 391*bb4ee6a4SAndroid Build Coastguard Worker sharing: image_sharing, 392*bb4ee6a4SAndroid Build Coastguard Worker initial_layout: image_initial_layout, 393*bb4ee6a4SAndroid Build Coastguard Worker external_memory_handle_types: create_post_image_external_memory_handle_types(), 394*bb4ee6a4SAndroid Build Coastguard Worker mutable_format, 395*bb4ee6a4SAndroid Build Coastguard Worker cube_compatible, 396*bb4ee6a4SAndroid Build Coastguard Worker array_2d_compatible, 397*bb4ee6a4SAndroid Build Coastguard Worker block_texel_view_compatible, 398*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 399*bb4ee6a4SAndroid Build Coastguard Worker }, 400*bb4ee6a4SAndroid Build Coastguard Worker MemoryAllocateInfo { 401*bb4ee6a4SAndroid Build Coastguard Worker allocation_size: metadata.allocation_size, 402*bb4ee6a4SAndroid Build Coastguard Worker memory_type_index: metadata.memory_type_index, 403*bb4ee6a4SAndroid Build Coastguard Worker export_handle_types: ExternalMemoryHandleTypes::empty(), 404*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 405*bb4ee6a4SAndroid Build Coastguard Worker }, 406*bb4ee6a4SAndroid Build Coastguard Worker create_post_image_memory_import_info(descriptor), 407*bb4ee6a4SAndroid Build Coastguard Worker metadata.dedicated_allocation, 408*bb4ee6a4SAndroid Build Coastguard Worker 0, 409*bb4ee6a4SAndroid Build Coastguard Worker ) 410*bb4ee6a4SAndroid Build Coastguard Worker .context("import the composition result image")?; 411*bb4ee6a4SAndroid Build Coastguard Worker 412*bb4ee6a4SAndroid Build Coastguard Worker if self.imported_images.insert(image_id, image).is_some() { 413*bb4ee6a4SAndroid Build Coastguard Worker warn!("Reused image_id {}", image_id); 414*bb4ee6a4SAndroid Build Coastguard Worker } 415*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 416*bb4ee6a4SAndroid Build Coastguard Worker } 417*bb4ee6a4SAndroid Build Coastguard Worker delete_imported_image_or_semaphore(&mut self, import_id: u32)418*bb4ee6a4SAndroid Build Coastguard Worker pub fn delete_imported_image_or_semaphore(&mut self, import_id: u32) { 419*bb4ee6a4SAndroid Build Coastguard Worker // Import ids are shared between images and semaphores, so first try to remove from 420*bb4ee6a4SAndroid Build Coastguard Worker // self.imported_sempahores, and if that returns none then try to remove from images. 421*bb4ee6a4SAndroid Build Coastguard Worker if self.imported_semaphores.remove(&import_id).is_none() { 422*bb4ee6a4SAndroid Build Coastguard Worker if let Some(receiver) = self.used_image_receivers.remove(&import_id) { 423*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = receiver.recv() { 424*bb4ee6a4SAndroid Build Coastguard Worker error!("Failed to receive used image from post worker: {}", e); 425*bb4ee6a4SAndroid Build Coastguard Worker } 426*bb4ee6a4SAndroid Build Coastguard Worker } else if self.imported_images.remove(&import_id).is_none() { 427*bb4ee6a4SAndroid Build Coastguard Worker error!("Import id {} has not been imported", import_id); 428*bb4ee6a4SAndroid Build Coastguard Worker } 429*bb4ee6a4SAndroid Build Coastguard Worker } 430*bb4ee6a4SAndroid Build Coastguard Worker } 431*bb4ee6a4SAndroid Build Coastguard Worker post( &mut self, image_id: ImageId, last_layout_transition: (i32, i32), acquire_semaphore: Option<SemaphoreTimepoint>, release_semaphore: SemaphoreTimepoint, ) -> Result<Waitable>432*bb4ee6a4SAndroid Build Coastguard Worker pub fn post( 433*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 434*bb4ee6a4SAndroid Build Coastguard Worker image_id: ImageId, 435*bb4ee6a4SAndroid Build Coastguard Worker last_layout_transition: (i32, i32), 436*bb4ee6a4SAndroid Build Coastguard Worker acquire_semaphore: Option<SemaphoreTimepoint>, 437*bb4ee6a4SAndroid Build Coastguard Worker release_semaphore: SemaphoreTimepoint, 438*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Waitable> { 439*bb4ee6a4SAndroid Build Coastguard Worker let image = if let Some(receiver) = self.used_image_receivers.remove(&image_id) { 440*bb4ee6a4SAndroid Build Coastguard Worker receiver 441*bb4ee6a4SAndroid Build Coastguard Worker .recv() 442*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to receive used image from post worker")? 443*bb4ee6a4SAndroid Build Coastguard Worker } else { 444*bb4ee6a4SAndroid Build Coastguard Worker self.imported_images 445*bb4ee6a4SAndroid Build Coastguard Worker .remove(&image_id) 446*bb4ee6a4SAndroid Build Coastguard Worker .ok_or(anyhow!("Image id {} has not been imported", image_id))? 447*bb4ee6a4SAndroid Build Coastguard Worker }; 448*bb4ee6a4SAndroid Build Coastguard Worker 449*bb4ee6a4SAndroid Build Coastguard Worker let acquire_timepoint = 450*bb4ee6a4SAndroid Build Coastguard Worker if let Some(SemaphoreTimepoint { import_id, value }) = acquire_semaphore { 451*bb4ee6a4SAndroid Build Coastguard Worker let semaphore = self 452*bb4ee6a4SAndroid Build Coastguard Worker .imported_semaphores 453*bb4ee6a4SAndroid Build Coastguard Worker .get(&import_id) 454*bb4ee6a4SAndroid Build Coastguard Worker .ok_or(anyhow!("Semaphore id {} has not been imported", import_id))?; 455*bb4ee6a4SAndroid Build Coastguard Worker Some(Timepoint { 456*bb4ee6a4SAndroid Build Coastguard Worker semaphore: semaphore.clone(), 457*bb4ee6a4SAndroid Build Coastguard Worker value, 458*bb4ee6a4SAndroid Build Coastguard Worker }) 459*bb4ee6a4SAndroid Build Coastguard Worker } else { 460*bb4ee6a4SAndroid Build Coastguard Worker None 461*bb4ee6a4SAndroid Build Coastguard Worker }; 462*bb4ee6a4SAndroid Build Coastguard Worker 463*bb4ee6a4SAndroid Build Coastguard Worker let release_timepoint = { 464*bb4ee6a4SAndroid Build Coastguard Worker let semaphore = self 465*bb4ee6a4SAndroid Build Coastguard Worker .imported_semaphores 466*bb4ee6a4SAndroid Build Coastguard Worker .get(&release_semaphore.import_id) 467*bb4ee6a4SAndroid Build Coastguard Worker .ok_or(anyhow!( 468*bb4ee6a4SAndroid Build Coastguard Worker "Semaphore id {} has not been imported", 469*bb4ee6a4SAndroid Build Coastguard Worker release_semaphore.import_id 470*bb4ee6a4SAndroid Build Coastguard Worker ))?; 471*bb4ee6a4SAndroid Build Coastguard Worker Timepoint { 472*bb4ee6a4SAndroid Build Coastguard Worker semaphore: semaphore.clone(), 473*bb4ee6a4SAndroid Build Coastguard Worker value: release_semaphore.value, 474*bb4ee6a4SAndroid Build Coastguard Worker } 475*bb4ee6a4SAndroid Build Coastguard Worker }; 476*bb4ee6a4SAndroid Build Coastguard Worker 477*bb4ee6a4SAndroid Build Coastguard Worker let last_layout_transition: (ImageLayout, ImageLayout) = ( 478*bb4ee6a4SAndroid Build Coastguard Worker ash::vk::ImageLayout::from_raw(last_layout_transition.0) 479*bb4ee6a4SAndroid Build Coastguard Worker .try_into() 480*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| { 481*bb4ee6a4SAndroid Build Coastguard Worker anyhow!( 482*bb4ee6a4SAndroid Build Coastguard Worker "Failed to convert {:#x} to a valid image layout.", 483*bb4ee6a4SAndroid Build Coastguard Worker last_layout_transition.0 484*bb4ee6a4SAndroid Build Coastguard Worker ) 485*bb4ee6a4SAndroid Build Coastguard Worker })?, 486*bb4ee6a4SAndroid Build Coastguard Worker ash::vk::ImageLayout::from_raw(last_layout_transition.1) 487*bb4ee6a4SAndroid Build Coastguard Worker .try_into() 488*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| { 489*bb4ee6a4SAndroid Build Coastguard Worker anyhow!( 490*bb4ee6a4SAndroid Build Coastguard Worker "Failed to convert {:#x} to a valid image layout.", 491*bb4ee6a4SAndroid Build Coastguard Worker last_layout_transition.1 492*bb4ee6a4SAndroid Build Coastguard Worker ) 493*bb4ee6a4SAndroid Build Coastguard Worker })?, 494*bb4ee6a4SAndroid Build Coastguard Worker ); 495*bb4ee6a4SAndroid Build Coastguard Worker 496*bb4ee6a4SAndroid Build Coastguard Worker let (promise, waitable) = create_promise_and_waitable(); 497*bb4ee6a4SAndroid Build Coastguard Worker 498*bb4ee6a4SAndroid Build Coastguard Worker let (image_return_tx, image_return_rx) = channel(); 499*bb4ee6a4SAndroid Build Coastguard Worker self.used_image_receivers.insert(image_id, image_return_rx); 500*bb4ee6a4SAndroid Build Coastguard Worker 501*bb4ee6a4SAndroid Build Coastguard Worker self.window_event_loop 502*bb4ee6a4SAndroid Build Coastguard Worker .send_event(UserEvent::PostCommand { 503*bb4ee6a4SAndroid Build Coastguard Worker image, 504*bb4ee6a4SAndroid Build Coastguard Worker last_layout_transition, 505*bb4ee6a4SAndroid Build Coastguard Worker acquire_timepoint, 506*bb4ee6a4SAndroid Build Coastguard Worker release_timepoint, 507*bb4ee6a4SAndroid Build Coastguard Worker image_return: image_return_tx, 508*bb4ee6a4SAndroid Build Coastguard Worker promise, 509*bb4ee6a4SAndroid Build Coastguard Worker }) 510*bb4ee6a4SAndroid Build Coastguard Worker .context("send user defined message to the window event loop")?; 511*bb4ee6a4SAndroid Build Coastguard Worker Ok(waitable) 512*bb4ee6a4SAndroid Build Coastguard Worker } 513*bb4ee6a4SAndroid Build Coastguard Worker } 514*bb4ee6a4SAndroid Build Coastguard Worker 515*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) type VulkanDisplay = VulkanDisplayImpl<PlatformWindowEventLoop<VulkanState>>; 516