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