1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 use super::{
11     ColorSpace, CompositeAlpha, CompositeAlphas, PresentMode, Surface, SurfaceTransform,
12     SurfaceTransforms, SwapchainPresentInfo,
13 };
14 use crate::{
15     buffer::Buffer,
16     device::{Device, DeviceOwned, Queue},
17     format::Format,
18     image::{
19         sys::Image, ImageFormatInfo, ImageLayout, ImageTiling, ImageType, ImageUsage,
20         SwapchainImage,
21     },
22     macros::{impl_id_counter, vulkan_enum},
23     swapchain::{PresentInfo, SurfaceApi, SurfaceInfo, SurfaceSwapchainLock},
24     sync::{
25         fence::{Fence, FenceError},
26         future::{AccessCheckError, AccessError, FlushError, GpuFuture, SubmitAnyBuilder},
27         semaphore::{Semaphore, SemaphoreError},
28         Sharing,
29     },
30     DeviceSize, OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
31 };
32 use parking_lot::Mutex;
33 use smallvec::{smallvec, SmallVec};
34 use std::{
35     error::Error,
36     fmt::{Debug, Display, Error as FmtError, Formatter},
37     mem::MaybeUninit,
38     num::NonZeroU64,
39     ops::Range,
40     ptr,
41     sync::{
42         atomic::{AtomicBool, AtomicU64, Ordering},
43         Arc,
44     },
45     thread,
46     time::Duration,
47 };
48 
49 /// Contains the swapping system and the images that can be shown on a surface.
50 pub struct Swapchain {
51     handle: ash::vk::SwapchainKHR,
52     device: Arc<Device>,
53     surface: Arc<Surface>,
54     id: NonZeroU64,
55 
56     min_image_count: u32,
57     image_format: Format,
58     image_color_space: ColorSpace,
59     image_extent: [u32; 2],
60     image_array_layers: u32,
61     image_usage: ImageUsage,
62     image_sharing: Sharing<SmallVec<[u32; 4]>>,
63     pre_transform: SurfaceTransform,
64     composite_alpha: CompositeAlpha,
65     present_mode: PresentMode,
66     clipped: bool,
67     full_screen_exclusive: FullScreenExclusive,
68     win32_monitor: Option<Win32Monitor>,
69     prev_present_id: AtomicU64,
70 
71     // Whether full-screen exclusive is currently held.
72     full_screen_exclusive_held: AtomicBool,
73 
74     // The images of this swapchain.
75     images: Vec<ImageEntry>,
76 
77     // If true, that means we have tried to use this swapchain to recreate a new swapchain. The
78     // current swapchain can no longer be used for anything except presenting already-acquired
79     // images.
80     //
81     // We use a `Mutex` instead of an `AtomicBool` because we want to keep that locked while
82     // we acquire the image.
83     retired: Mutex<bool>,
84 }
85 
86 #[derive(Debug)]
87 struct ImageEntry {
88     handle: ash::vk::Image,
89     layout_initialized: AtomicBool,
90 }
91 
92 impl Swapchain {
93     /// Creates a new `Swapchain`.
94     ///
95     /// This function returns the swapchain plus a list of the images that belong to the
96     /// swapchain. The order in which the images are returned is important for the
97     /// `acquire_next_image` and `present` functions.
98     ///
99     /// # Panics
100     ///
101     /// - Panics if the device and the surface don't belong to the same instance.
102     /// - Panics if `create_info.usage` is empty.
103     ///
104     // TODO: isn't it unsafe to take the surface through an Arc when it comes to vulkano-win?
new( device: Arc<Device>, surface: Arc<Surface>, mut create_info: SwapchainCreateInfo, ) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), SwapchainCreationError>105     pub fn new(
106         device: Arc<Device>,
107         surface: Arc<Surface>,
108         mut create_info: SwapchainCreateInfo,
109     ) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), SwapchainCreationError> {
110         Self::validate(&device, &surface, &mut create_info)?;
111 
112         // Checking that the surface doesn't already have a swapchain.
113         if surface.flag().swap(true, Ordering::AcqRel) {
114             return Err(SwapchainCreationError::SurfaceInUse);
115         }
116 
117         let (handle, image_handles) =
118             unsafe { Self::create(&device, &surface, &create_info, None)? };
119 
120         let SwapchainCreateInfo {
121             min_image_count,
122             image_format,
123             image_color_space,
124             image_extent,
125             image_array_layers,
126             image_usage,
127             image_sharing,
128             pre_transform,
129             composite_alpha,
130             present_mode,
131             clipped,
132             full_screen_exclusive,
133             win32_monitor,
134             _ne: _,
135         } = create_info;
136 
137         let swapchain = Arc::new(Swapchain {
138             handle,
139             device,
140             surface,
141             id: Self::next_id(),
142             min_image_count,
143             image_format: image_format.unwrap(),
144             image_color_space,
145             image_extent,
146             image_array_layers,
147             image_usage,
148             image_sharing,
149             pre_transform,
150             composite_alpha,
151             present_mode,
152             clipped,
153             full_screen_exclusive,
154             win32_monitor,
155             prev_present_id: Default::default(),
156             full_screen_exclusive_held: AtomicBool::new(false),
157             images: image_handles
158                 .iter()
159                 .map(|&handle| ImageEntry {
160                     handle,
161                     layout_initialized: AtomicBool::new(false),
162                 })
163                 .collect(),
164             retired: Mutex::new(false),
165         });
166 
167         let swapchain_images = image_handles
168             .into_iter()
169             .enumerate()
170             .map(|(image_index, handle)| unsafe {
171                 SwapchainImage::from_handle(handle, swapchain.clone(), image_index as u32)
172             })
173             .collect::<Result<_, _>>()?;
174 
175         Ok((swapchain, swapchain_images))
176     }
177 
178     /// Creates a new swapchain from this one.
179     ///
180     /// Use this when a swapchain has become invalidated, such as due to window resizes.
181     ///
182     /// # Panics
183     ///
184     /// - Panics if `create_info.usage` is empty.
recreate( self: &Arc<Self>, mut create_info: SwapchainCreateInfo, ) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), SwapchainCreationError>185     pub fn recreate(
186         self: &Arc<Self>,
187         mut create_info: SwapchainCreateInfo,
188     ) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), SwapchainCreationError> {
189         Self::validate(&self.device, &self.surface, &mut create_info)?;
190 
191         {
192             let mut retired = self.retired.lock();
193 
194             // The swapchain has already been used to create a new one.
195             if *retired {
196                 return Err(SwapchainCreationError::SwapchainAlreadyRetired);
197             } else {
198                 // According to the documentation of VkSwapchainCreateInfoKHR:
199                 //
200                 // > Upon calling vkCreateSwapchainKHR with a oldSwapchain that is not VK_NULL_HANDLE,
201                 // > any images not acquired by the application may be freed by the implementation,
202                 // > which may occur even if creation of the new swapchain fails.
203                 //
204                 // Therefore, we set retired to true and keep it to true even if the call to `vkCreateSwapchainKHR` below fails.
205                 *retired = true;
206             }
207         }
208 
209         let (handle, image_handles) =
210             unsafe { Self::create(&self.device, &self.surface, &create_info, Some(self))? };
211 
212         let full_screen_exclusive_held =
213             if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
214                 false
215             } else {
216                 self.full_screen_exclusive_held.load(Ordering::SeqCst)
217             };
218 
219         let SwapchainCreateInfo {
220             min_image_count,
221             image_format,
222             image_color_space,
223             image_extent,
224             image_array_layers,
225             image_usage,
226             image_sharing,
227             pre_transform,
228             composite_alpha,
229             present_mode,
230             clipped,
231             full_screen_exclusive,
232             win32_monitor,
233             _ne: _,
234         } = create_info;
235 
236         let swapchain = Arc::new(Swapchain {
237             handle,
238             device: self.device.clone(),
239             surface: self.surface.clone(),
240             id: Self::next_id(),
241             min_image_count,
242             image_format: image_format.unwrap(),
243             image_color_space,
244             image_extent,
245             image_array_layers,
246             image_usage,
247             image_sharing,
248             pre_transform,
249             composite_alpha,
250             present_mode,
251             clipped,
252             full_screen_exclusive,
253             win32_monitor,
254             prev_present_id: Default::default(),
255             full_screen_exclusive_held: AtomicBool::new(full_screen_exclusive_held),
256             images: image_handles
257                 .iter()
258                 .map(|&handle| ImageEntry {
259                     handle,
260                     layout_initialized: AtomicBool::new(false),
261                 })
262                 .collect(),
263             retired: Mutex::new(false),
264         });
265 
266         let swapchain_images = image_handles
267             .into_iter()
268             .enumerate()
269             .map(|(image_index, handle)| unsafe {
270                 SwapchainImage::from_handle(handle, swapchain.clone(), image_index as u32)
271             })
272             .collect::<Result<_, _>>()?;
273 
274         Ok((swapchain, swapchain_images))
275     }
276 
validate( device: &Device, surface: &Surface, create_info: &mut SwapchainCreateInfo, ) -> Result<(), SwapchainCreationError>277     fn validate(
278         device: &Device,
279         surface: &Surface,
280         create_info: &mut SwapchainCreateInfo,
281     ) -> Result<(), SwapchainCreationError> {
282         let &mut SwapchainCreateInfo {
283             min_image_count,
284             ref mut image_format,
285             image_color_space,
286             ref mut image_extent,
287             image_array_layers,
288             image_usage,
289             ref mut image_sharing,
290             pre_transform,
291             composite_alpha,
292             present_mode,
293             clipped: _,
294             full_screen_exclusive,
295             win32_monitor,
296             _ne: _,
297         } = create_info;
298 
299         if !device.enabled_extensions().khr_swapchain {
300             return Err(SwapchainCreationError::RequirementNotMet {
301                 required_for: "`Swapchain::new`",
302                 requires_one_of: RequiresOneOf {
303                     device_extensions: &["khr_swapchain"],
304                     ..Default::default()
305                 },
306             });
307         }
308 
309         assert_eq!(device.instance(), surface.instance());
310 
311         // VUID-VkSwapchainCreateInfoKHR-imageColorSpace-parameter
312         image_color_space.validate_device(device)?;
313 
314         // VUID-VkSwapchainCreateInfoKHR-imageUsage-parameter
315         image_usage.validate_device(device)?;
316 
317         // VUID-VkSwapchainCreateInfoKHR-imageUsage-requiredbitmask
318         assert!(!image_usage.is_empty());
319 
320         // VUID-VkSwapchainCreateInfoKHR-preTransform-parameter
321         pre_transform.validate_device(device)?;
322 
323         // VUID-VkSwapchainCreateInfoKHR-compositeAlpha-parameter
324         composite_alpha.validate_device(device)?;
325 
326         // VUID-VkSwapchainCreateInfoKHR-presentMode-parameter
327         present_mode.validate_device(device)?;
328 
329         if full_screen_exclusive != FullScreenExclusive::Default {
330             if !device.enabled_extensions().ext_full_screen_exclusive {
331                 return Err(SwapchainCreationError::RequirementNotMet {
332                     required_for: "`create_info.full_screen_exclusive` is not \
333                         `FullScreenExclusive::Default`",
334                     requires_one_of: RequiresOneOf {
335                         device_extensions: &["ext_full_screen_exclusive"],
336                         ..Default::default()
337                     },
338                 });
339             }
340 
341             // VUID-VkSurfaceFullScreenExclusiveInfoEXT-fullScreenExclusive-parameter
342             full_screen_exclusive.validate_device(device)?;
343         }
344 
345         if surface.api() == SurfaceApi::Win32
346             && full_screen_exclusive == FullScreenExclusive::ApplicationControlled
347         {
348             if win32_monitor.is_none() {
349                 return Err(SwapchainCreationError::Win32MonitorInvalid);
350             }
351         } else {
352             if win32_monitor.is_some() {
353                 return Err(SwapchainCreationError::Win32MonitorInvalid);
354             }
355         }
356 
357         // VUID-VkSwapchainCreateInfoKHR-surface-01270
358         if !device
359             .active_queue_family_indices()
360             .iter()
361             .copied()
362             .any(|index| unsafe {
363                 // Use unchecked, because all validation has been done above.
364                 device
365                     .physical_device()
366                     .surface_support_unchecked(index, surface)
367                     .unwrap_or_default()
368             })
369         {
370             return Err(SwapchainCreationError::SurfaceNotSupported);
371         }
372 
373         *image_format = Some({
374             // Use unchecked, because all validation has been done above.
375             let surface_formats = unsafe {
376                 device.physical_device().surface_formats_unchecked(
377                     surface,
378                     SurfaceInfo {
379                         full_screen_exclusive,
380                         win32_monitor,
381                         ..Default::default()
382                     },
383                 )?
384             };
385 
386             if let Some(format) = image_format {
387                 // VUID-VkSwapchainCreateInfoKHR-imageFormat-parameter
388                 format.validate_device(device)?;
389 
390                 // VUID-VkSwapchainCreateInfoKHR-imageFormat-01273
391                 if !surface_formats
392                     .into_iter()
393                     .any(|(f, c)| f == *format && c == image_color_space)
394                 {
395                     return Err(SwapchainCreationError::FormatColorSpaceNotSupported);
396                 }
397                 *format
398             } else {
399                 surface_formats
400                     .into_iter()
401                     .find_map(|(f, c)| {
402                         (c == image_color_space
403                             && [Format::R8G8B8A8_UNORM, Format::B8G8R8A8_UNORM].contains(&f))
404                         .then_some(f)
405                     })
406                     .ok_or(SwapchainCreationError::FormatColorSpaceNotSupported)?
407             }
408         });
409 
410         // Use unchecked, because all validation has been done above.
411         let surface_capabilities = unsafe {
412             device.physical_device().surface_capabilities_unchecked(
413                 surface,
414                 SurfaceInfo {
415                     full_screen_exclusive,
416                     win32_monitor,
417                     ..Default::default()
418                 },
419             )?
420         };
421 
422         // VUID-VkSwapchainCreateInfoKHR-minImageCount-01272
423         // VUID-VkSwapchainCreateInfoKHR-presentMode-02839
424         if min_image_count < surface_capabilities.min_image_count
425             || surface_capabilities
426                 .max_image_count
427                 .map_or(false, |c| min_image_count > c)
428         {
429             return Err(SwapchainCreationError::MinImageCountNotSupported {
430                 provided: min_image_count,
431                 min_supported: surface_capabilities.min_image_count,
432                 max_supported: surface_capabilities.max_image_count,
433             });
434         }
435 
436         if image_extent[0] == 0 || image_extent[1] == 0 {
437             *image_extent = surface_capabilities.current_extent.unwrap();
438         }
439 
440         // VUID-VkSwapchainCreateInfoKHR-imageExtent-01274
441         if image_extent[0] < surface_capabilities.min_image_extent[0]
442             || image_extent[1] < surface_capabilities.min_image_extent[1]
443             || image_extent[0] > surface_capabilities.max_image_extent[0]
444             || image_extent[1] > surface_capabilities.max_image_extent[1]
445         {
446             return Err(SwapchainCreationError::ImageExtentNotSupported {
447                 provided: *image_extent,
448                 min_supported: surface_capabilities.min_image_extent,
449                 max_supported: surface_capabilities.max_image_extent,
450             });
451         }
452 
453         // VUID-VkSwapchainCreateInfoKHR-imageExtent-01689
454         // On some platforms, dimensions of zero-length can occur by minimizing the surface.
455         if image_extent.contains(&0) {
456             return Err(SwapchainCreationError::ImageExtentZeroLengthDimensions);
457         }
458 
459         // VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275
460         if image_array_layers == 0
461             || image_array_layers > surface_capabilities.max_image_array_layers
462         {
463             return Err(SwapchainCreationError::ImageArrayLayersNotSupported {
464                 provided: image_array_layers,
465                 max_supported: surface_capabilities.max_image_array_layers,
466             });
467         }
468 
469         // VUID-VkSwapchainCreateInfoKHR-presentMode-01427
470         if (ash::vk::ImageUsageFlags::from(image_usage)
471             & ash::vk::ImageUsageFlags::from(surface_capabilities.supported_usage_flags))
472             != ash::vk::ImageUsageFlags::from(image_usage)
473         {
474             return Err(SwapchainCreationError::ImageUsageNotSupported {
475                 provided: image_usage,
476                 supported: surface_capabilities.supported_usage_flags,
477             });
478         }
479 
480         match image_sharing {
481             Sharing::Exclusive => (),
482             Sharing::Concurrent(queue_family_indices) => {
483                 // VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01278
484                 // VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01428
485                 queue_family_indices.sort_unstable();
486                 queue_family_indices.dedup();
487                 assert!(queue_family_indices.len() >= 2);
488 
489                 for &queue_family_index in queue_family_indices.iter() {
490                     // VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01428
491                     if queue_family_index
492                         >= device.physical_device().queue_family_properties().len() as u32
493                     {
494                         return Err(
495                             SwapchainCreationError::ImageSharingQueueFamilyIndexOutOfRange {
496                                 queue_family_index,
497                                 queue_family_count: device
498                                     .physical_device()
499                                     .queue_family_properties()
500                                     .len()
501                                     as u32,
502                             },
503                         );
504                     }
505                 }
506             }
507         };
508 
509         // VUID-VkSwapchainCreateInfoKHR-preTransform-01279
510         if !surface_capabilities
511             .supported_transforms
512             .contains_enum(pre_transform)
513         {
514             return Err(SwapchainCreationError::PreTransformNotSupported {
515                 provided: pre_transform,
516                 supported: surface_capabilities.supported_transforms,
517             });
518         }
519 
520         // VUID-VkSwapchainCreateInfoKHR-compositeAlpha-01280
521         if !surface_capabilities
522             .supported_composite_alpha
523             .contains_enum(composite_alpha)
524         {
525             return Err(SwapchainCreationError::CompositeAlphaNotSupported {
526                 provided: composite_alpha,
527                 supported: surface_capabilities.supported_composite_alpha,
528             });
529         }
530 
531         // VUID-VkSwapchainCreateInfoKHR-presentMode-01281
532         // Use unchecked, because all validation has been done above.
533         if !unsafe {
534             device
535                 .physical_device()
536                 .surface_present_modes_unchecked(surface)?
537         }
538         .any(|mode| mode == present_mode)
539         {
540             return Err(SwapchainCreationError::PresentModeNotSupported);
541         }
542 
543         // VUID-VkSwapchainCreateInfoKHR-imageFormat-01778
544         // Use unchecked, because all validation has been done above.
545         if unsafe {
546             device
547                 .physical_device()
548                 .image_format_properties_unchecked(ImageFormatInfo {
549                     format: *image_format,
550                     image_type: ImageType::Dim2d,
551                     tiling: ImageTiling::Optimal,
552                     usage: image_usage,
553                     ..Default::default()
554                 })?
555         }
556         .is_none()
557         {
558             return Err(SwapchainCreationError::ImageFormatPropertiesNotSupported);
559         }
560 
561         Ok(())
562     }
563 
create( device: &Device, surface: &Surface, create_info: &SwapchainCreateInfo, old_swapchain: Option<&Swapchain>, ) -> Result<(ash::vk::SwapchainKHR, Vec<ash::vk::Image>), SwapchainCreationError>564     unsafe fn create(
565         device: &Device,
566         surface: &Surface,
567         create_info: &SwapchainCreateInfo,
568         old_swapchain: Option<&Swapchain>,
569     ) -> Result<(ash::vk::SwapchainKHR, Vec<ash::vk::Image>), SwapchainCreationError> {
570         let &SwapchainCreateInfo {
571             min_image_count,
572             image_format,
573             image_color_space,
574             image_extent,
575             image_array_layers,
576             image_usage,
577             ref image_sharing,
578             pre_transform,
579             composite_alpha,
580             present_mode,
581             clipped,
582             full_screen_exclusive,
583             win32_monitor,
584             _ne: _,
585         } = create_info;
586 
587         let (image_sharing_mode, queue_family_index_count, p_queue_family_indices) =
588             match image_sharing {
589                 Sharing::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, 0, ptr::null()),
590                 Sharing::Concurrent(ref ids) => (
591                     ash::vk::SharingMode::CONCURRENT,
592                     ids.len() as u32,
593                     ids.as_ptr(),
594                 ),
595             };
596 
597         let mut info_vk = ash::vk::SwapchainCreateInfoKHR {
598             flags: ash::vk::SwapchainCreateFlagsKHR::empty(),
599             surface: surface.handle(),
600             min_image_count,
601             image_format: image_format.unwrap().into(),
602             image_color_space: image_color_space.into(),
603             image_extent: ash::vk::Extent2D {
604                 width: image_extent[0],
605                 height: image_extent[1],
606             },
607             image_array_layers,
608             image_usage: image_usage.into(),
609             image_sharing_mode,
610             queue_family_index_count,
611             p_queue_family_indices,
612             pre_transform: pre_transform.into(),
613             composite_alpha: composite_alpha.into(),
614             present_mode: present_mode.into(),
615             clipped: clipped as ash::vk::Bool32,
616             old_swapchain: old_swapchain.map_or(ash::vk::SwapchainKHR::null(), |os| os.handle),
617             ..Default::default()
618         };
619         let mut surface_full_screen_exclusive_info_vk = None;
620         let mut surface_full_screen_exclusive_win32_info_vk = None;
621 
622         if full_screen_exclusive != FullScreenExclusive::Default {
623             let next = surface_full_screen_exclusive_info_vk.insert(
624                 ash::vk::SurfaceFullScreenExclusiveInfoEXT {
625                     full_screen_exclusive: full_screen_exclusive.into(),
626                     ..Default::default()
627                 },
628             );
629 
630             next.p_next = info_vk.p_next as *mut _;
631             info_vk.p_next = next as *const _ as *const _;
632         }
633 
634         if let Some(Win32Monitor(hmonitor)) = win32_monitor {
635             let next = surface_full_screen_exclusive_win32_info_vk.insert(
636                 ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
637                     hmonitor,
638                     ..Default::default()
639                 },
640             );
641 
642             next.p_next = info_vk.p_next as *mut _;
643             info_vk.p_next = next as *const _ as *const _;
644         }
645 
646         let fns = device.fns();
647 
648         let handle = {
649             let mut output = MaybeUninit::uninit();
650             (fns.khr_swapchain.create_swapchain_khr)(
651                 device.handle(),
652                 &info_vk,
653                 ptr::null(),
654                 output.as_mut_ptr(),
655             )
656             .result()
657             .map_err(VulkanError::from)?;
658             output.assume_init()
659         };
660 
661         let image_handles = loop {
662             let mut count = 0;
663             (fns.khr_swapchain.get_swapchain_images_khr)(
664                 device.handle(),
665                 handle,
666                 &mut count,
667                 ptr::null_mut(),
668             )
669             .result()
670             .map_err(VulkanError::from)?;
671 
672             let mut images = Vec::with_capacity(count as usize);
673             let result = (fns.khr_swapchain.get_swapchain_images_khr)(
674                 device.handle(),
675                 handle,
676                 &mut count,
677                 images.as_mut_ptr(),
678             );
679 
680             match result {
681                 ash::vk::Result::SUCCESS => {
682                     images.set_len(count as usize);
683                     break images;
684                 }
685                 ash::vk::Result::INCOMPLETE => (),
686                 err => return Err(VulkanError::from(err).into()),
687             }
688         };
689 
690         Ok((handle, image_handles))
691     }
692 
693     /// Returns the creation parameters of the swapchain.
694     #[inline]
create_info(&self) -> SwapchainCreateInfo695     pub fn create_info(&self) -> SwapchainCreateInfo {
696         SwapchainCreateInfo {
697             min_image_count: self.min_image_count,
698             image_format: Some(self.image_format),
699             image_color_space: self.image_color_space,
700             image_extent: self.image_extent,
701             image_array_layers: self.image_array_layers,
702             image_usage: self.image_usage,
703             image_sharing: self.image_sharing.clone(),
704             pre_transform: self.pre_transform,
705             composite_alpha: self.composite_alpha,
706             present_mode: self.present_mode,
707             clipped: self.clipped,
708             full_screen_exclusive: self.full_screen_exclusive,
709             win32_monitor: self.win32_monitor,
710             _ne: crate::NonExhaustive(()),
711         }
712     }
713 
714     /// Returns the saved Surface, from the Swapchain creation.
715     #[inline]
surface(&self) -> &Arc<Surface>716     pub fn surface(&self) -> &Arc<Surface> {
717         &self.surface
718     }
719 
720     /// If `image` is one of the images of this swapchain, returns its index within the swapchain.
721     #[inline]
index_of_image(&self, image: &Image) -> Option<u32>722     pub fn index_of_image(&self, image: &Image) -> Option<u32> {
723         self.images
724             .iter()
725             .position(|entry| entry.handle == image.handle())
726             .map(|i| i as u32)
727     }
728 
729     /// Returns the number of images of the swapchain.
730     #[inline]
image_count(&self) -> u32731     pub fn image_count(&self) -> u32 {
732         self.images.len() as u32
733     }
734 
735     /// Returns the format of the images of the swapchain.
736     #[inline]
image_format(&self) -> Format737     pub fn image_format(&self) -> Format {
738         self.image_format
739     }
740 
741     /// Returns the color space of the images of the swapchain.
742     #[inline]
image_color_space(&self) -> ColorSpace743     pub fn image_color_space(&self) -> ColorSpace {
744         self.image_color_space
745     }
746 
747     /// Returns the extent of the images of the swapchain.
748     #[inline]
image_extent(&self) -> [u32; 2]749     pub fn image_extent(&self) -> [u32; 2] {
750         self.image_extent
751     }
752 
753     /// Returns the number of array layers of the images of the swapchain.
754     #[inline]
image_array_layers(&self) -> u32755     pub fn image_array_layers(&self) -> u32 {
756         self.image_array_layers
757     }
758 
759     /// Returns the usage of the images of the swapchain.
760     #[inline]
image_usage(&self) -> ImageUsage761     pub fn image_usage(&self) -> ImageUsage {
762         self.image_usage
763     }
764 
765     /// Returns the sharing of the images of the swapchain.
766     #[inline]
image_sharing(&self) -> &Sharing<SmallVec<[u32; 4]>>767     pub fn image_sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
768         &self.image_sharing
769     }
770 
771     #[inline]
full_screen_exclusive_held(&self) -> &AtomicBool772     pub(crate) unsafe fn full_screen_exclusive_held(&self) -> &AtomicBool {
773         &self.full_screen_exclusive_held
774     }
775 
776     #[inline]
try_claim_present_id(&self, present_id: NonZeroU64) -> bool777     pub(crate) unsafe fn try_claim_present_id(&self, present_id: NonZeroU64) -> bool {
778         let present_id = u64::from(present_id);
779         self.prev_present_id.fetch_max(present_id, Ordering::SeqCst) < present_id
780     }
781 
782     /// Returns the pre-transform that was passed when creating the swapchain.
783     #[inline]
pre_transform(&self) -> SurfaceTransform784     pub fn pre_transform(&self) -> SurfaceTransform {
785         self.pre_transform
786     }
787 
788     /// Returns the alpha mode that was passed when creating the swapchain.
789     #[inline]
composite_alpha(&self) -> CompositeAlpha790     pub fn composite_alpha(&self) -> CompositeAlpha {
791         self.composite_alpha
792     }
793 
794     /// Returns the present mode that was passed when creating the swapchain.
795     #[inline]
present_mode(&self) -> PresentMode796     pub fn present_mode(&self) -> PresentMode {
797         self.present_mode
798     }
799 
800     /// Returns the value of `clipped` that was passed when creating the swapchain.
801     #[inline]
clipped(&self) -> bool802     pub fn clipped(&self) -> bool {
803         self.clipped
804     }
805 
806     /// Returns the value of 'full_screen_exclusive` that was passed when creating the swapchain.
807     #[inline]
full_screen_exclusive(&self) -> FullScreenExclusive808     pub fn full_screen_exclusive(&self) -> FullScreenExclusive {
809         self.full_screen_exclusive
810     }
811 
812     /// Acquires full-screen exclusivity.
813     ///
814     /// The swapchain must have been created with [`FullScreenExclusive::ApplicationControlled`],
815     /// and must not already hold full-screen exclusivity. Full-screen exclusivity is held until
816     /// either the `release_full_screen_exclusive` is called, or if any of the the other `Swapchain`
817     /// functions return `FullScreenExclusiveLost`.
818     #[inline]
acquire_full_screen_exclusive(&self) -> Result<(), FullScreenExclusiveError>819     pub fn acquire_full_screen_exclusive(&self) -> Result<(), FullScreenExclusiveError> {
820         if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
821             return Err(FullScreenExclusiveError::NotApplicationControlled);
822         }
823 
824         if self.full_screen_exclusive_held.swap(true, Ordering::SeqCst) {
825             return Err(FullScreenExclusiveError::DoubleAcquire);
826         }
827 
828         unsafe {
829             let fns = self.device.fns();
830             (fns.ext_full_screen_exclusive
831                 .acquire_full_screen_exclusive_mode_ext)(
832                 self.device.handle(), self.handle
833             )
834             .result()
835             .map_err(VulkanError::from)?;
836         }
837 
838         Ok(())
839     }
840 
841     /// Releases full-screen exclusivity.
842     ///
843     /// The swapchain must have been created with [`FullScreenExclusive::ApplicationControlled`],
844     /// and must currently hold full-screen exclusivity.
845     #[inline]
release_full_screen_exclusive(&self) -> Result<(), FullScreenExclusiveError>846     pub fn release_full_screen_exclusive(&self) -> Result<(), FullScreenExclusiveError> {
847         if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
848             return Err(FullScreenExclusiveError::NotApplicationControlled);
849         }
850 
851         if !self
852             .full_screen_exclusive_held
853             .swap(false, Ordering::SeqCst)
854         {
855             return Err(FullScreenExclusiveError::DoubleRelease);
856         }
857 
858         unsafe {
859             let fns = self.device.fns();
860             (fns.ext_full_screen_exclusive
861                 .release_full_screen_exclusive_mode_ext)(
862                 self.device.handle(), self.handle
863             )
864             .result()
865             .map_err(VulkanError::from)?;
866         }
867 
868         Ok(())
869     }
870 
871     /// `FullScreenExclusive::AppControlled` is not the active full-screen exclusivity mode,
872     /// then this function will always return false. If true is returned the swapchain
873     /// is in `FullScreenExclusive::AppControlled` full-screen exclusivity mode and exclusivity
874     /// is currently acquired.
875     #[inline]
is_full_screen_exclusive(&self) -> bool876     pub fn is_full_screen_exclusive(&self) -> bool {
877         if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
878             false
879         } else {
880             self.full_screen_exclusive_held.load(Ordering::SeqCst)
881         }
882     }
883 
884     // This method is necessary to allow `SwapchainImage`s to signal when they have been
885     // transitioned out of their initial `undefined` image layout.
886     //
887     // See the `ImageAccess::layout_initialized` method documentation for more details.
image_layout_initialized(&self, image_index: u32)888     pub(crate) fn image_layout_initialized(&self, image_index: u32) {
889         let image_entry = self.images.get(image_index as usize);
890         if let Some(image_entry) = image_entry {
891             image_entry
892                 .layout_initialized
893                 .store(true, Ordering::Relaxed);
894         }
895     }
896 
is_image_layout_initialized(&self, image_index: u32) -> bool897     pub(crate) fn is_image_layout_initialized(&self, image_index: u32) -> bool {
898         let image_entry = self.images.get(image_index as usize);
899         if let Some(image_entry) = image_entry {
900             image_entry.layout_initialized.load(Ordering::Relaxed)
901         } else {
902             false
903         }
904     }
905 }
906 
907 impl Drop for Swapchain {
908     #[inline]
drop(&mut self)909     fn drop(&mut self) {
910         unsafe {
911             let fns = self.device.fns();
912             (fns.khr_swapchain.destroy_swapchain_khr)(
913                 self.device.handle(),
914                 self.handle,
915                 ptr::null(),
916             );
917             self.surface.flag().store(false, Ordering::Release);
918         }
919     }
920 }
921 
922 unsafe impl VulkanObject for Swapchain {
923     type Handle = ash::vk::SwapchainKHR;
924 
925     #[inline]
handle(&self) -> Self::Handle926     fn handle(&self) -> Self::Handle {
927         self.handle
928     }
929 }
930 
931 unsafe impl DeviceOwned for Swapchain {
932     #[inline]
device(&self) -> &Arc<Device>933     fn device(&self) -> &Arc<Device> {
934         &self.device
935     }
936 }
937 
938 impl_id_counter!(Swapchain);
939 
940 impl Debug for Swapchain {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>941     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
942         let Self {
943             handle,
944             device,
945             surface,
946             id: _,
947             min_image_count,
948             image_format,
949             image_color_space,
950             image_extent,
951             image_array_layers,
952             image_usage,
953             image_sharing,
954             pre_transform,
955             composite_alpha,
956             present_mode,
957             clipped,
958             full_screen_exclusive,
959             win32_monitor,
960             prev_present_id,
961             full_screen_exclusive_held,
962             images,
963             retired,
964         } = self;
965 
966         f.debug_struct("Swapchain")
967             .field("handle", &handle)
968             .field("device", &device.handle())
969             .field("surface", &surface.handle())
970             .field("min_image_count", &min_image_count)
971             .field("image_format", &image_format)
972             .field("image_color_space", &image_color_space)
973             .field("image_extent", &image_extent)
974             .field("image_array_layers", &image_array_layers)
975             .field("image_usage", &image_usage)
976             .field("image_sharing", &image_sharing)
977             .field("pre_transform", &pre_transform)
978             .field("composite_alpha", &composite_alpha)
979             .field("present_mode", &present_mode)
980             .field("clipped", &clipped)
981             .field("full_screen_exclusive", &full_screen_exclusive)
982             .field("win32_monitor", &win32_monitor)
983             .field("prev_present_id", &prev_present_id)
984             .field("full_screen_exclusive_held", &full_screen_exclusive_held)
985             .field("images", &images)
986             .field("retired", &retired)
987             .finish()
988     }
989 }
990 
991 /// Parameters to create a new `Swapchain`.
992 ///
993 /// Many of the values here must be supported by the physical device.
994 /// [`PhysicalDevice`](crate::device::physical::PhysicalDevice) has several
995 /// methods to query what is supported.
996 #[derive(Clone, Debug)]
997 pub struct SwapchainCreateInfo {
998     /// The minimum number of images that will be created.
999     ///
1000     /// The implementation is allowed to create more than this number, but never less.
1001     ///
1002     /// The default value is `2`.
1003     pub min_image_count: u32,
1004 
1005     /// The format of the created images.
1006     ///
1007     /// If set to `None`, [`Format::R8G8B8A8_UNORM`] or [`Format::B8G8R8A8_UNORM`] will be selected,
1008     /// based on which is supported by the surface.
1009     ///
1010     /// The default value is `None`.
1011     pub image_format: Option<Format>,
1012 
1013     /// The color space of the created images.
1014     ///
1015     /// The default value is [`ColorSpace::SrgbNonLinear`].
1016     pub image_color_space: ColorSpace,
1017 
1018     /// The extent of the created images.
1019     ///
1020     /// If any of the values is 0, the value of
1021     /// [`SurfaceCapabilities::current_extent`](crate::swapchain::SurfaceCapabilities) will be used.
1022     ///
1023     /// The default value is `[0, 0]`.
1024     pub image_extent: [u32; 2],
1025 
1026     /// The number of array layers of the created images.
1027     ///
1028     /// The default value is `1`.
1029     pub image_array_layers: u32,
1030 
1031     /// How the created images will be used.
1032     ///
1033     /// The default value is [`ImageUsage::empty()`], which must be overridden.
1034     pub image_usage: ImageUsage,
1035 
1036     /// Whether the created images can be shared across multiple queues, or are limited to a single
1037     /// queue.
1038     ///
1039     /// The default value is [`Sharing::Exclusive`].
1040     pub image_sharing: Sharing<SmallVec<[u32; 4]>>,
1041 
1042     /// The transform that should be applied to an image before it is presented.
1043     ///
1044     /// The default value is [`SurfaceTransform::Identity`].
1045     pub pre_transform: SurfaceTransform,
1046 
1047     /// How alpha values of the pixels in the image are to be treated.
1048     ///
1049     /// The default value is [`CompositeAlpha::Opaque`].
1050     pub composite_alpha: CompositeAlpha,
1051 
1052     /// How the swapchain should behave when multiple images are waiting in the queue to be
1053     /// presented.
1054     ///
1055     /// The default is [`PresentMode::Fifo`].
1056     pub present_mode: PresentMode,
1057 
1058     /// Whether the implementation is allowed to discard rendering operations that affect regions of
1059     /// the surface which aren't visible. This is important to take into account if your fragment
1060     /// shader has side-effects or if you want to read back the content of the image afterwards.
1061     ///
1062     /// The default value is `true`.
1063     pub clipped: bool,
1064 
1065     /// How full-screen exclusivity is to be handled.
1066     ///
1067     /// If set to anything other than [`FullScreenExclusive::Default`], then the
1068     /// [`ext_full_screen_exclusive`](crate::device::DeviceExtensions::ext_full_screen_exclusive)
1069     /// extension must be enabled on the device.
1070     ///
1071     /// The default value is [`FullScreenExclusive::Default`].
1072     pub full_screen_exclusive: FullScreenExclusive,
1073 
1074     /// For Win32 surfaces, if `full_screen_exclusive` is
1075     /// [`FullScreenExclusive::ApplicationControlled`], this specifies the monitor on which
1076     /// full-screen exclusivity should be used.
1077     ///
1078     /// For this case, the value must be `Some`, and for all others it must be `None`.
1079     ///
1080     /// The default value is `None`.
1081     pub win32_monitor: Option<Win32Monitor>,
1082 
1083     pub _ne: crate::NonExhaustive,
1084 }
1085 
1086 impl Default for SwapchainCreateInfo {
1087     #[inline]
default() -> Self1088     fn default() -> Self {
1089         Self {
1090             min_image_count: 2,
1091             image_format: None,
1092             image_color_space: ColorSpace::SrgbNonLinear,
1093             image_extent: [0, 0],
1094             image_array_layers: 1,
1095             image_usage: ImageUsage::empty(),
1096             image_sharing: Sharing::Exclusive,
1097             pre_transform: SurfaceTransform::Identity,
1098             composite_alpha: CompositeAlpha::Opaque,
1099             present_mode: PresentMode::Fifo,
1100             clipped: true,
1101             full_screen_exclusive: FullScreenExclusive::Default,
1102             win32_monitor: None,
1103             _ne: crate::NonExhaustive(()),
1104         }
1105     }
1106 }
1107 
1108 /// Error that can happen when creating a `Swapchain`.
1109 #[derive(Clone, Debug, PartialEq, Eq)]
1110 pub enum SwapchainCreationError {
1111     /// Not enough memory.
1112     OomError(OomError),
1113 
1114     /// The device was lost.
1115     DeviceLost,
1116 
1117     /// The surface was lost.
1118     SurfaceLost,
1119 
1120     /// The surface is already used by another swapchain.
1121     SurfaceInUse,
1122 
1123     /// The window is already in use by another API.
1124     NativeWindowInUse,
1125 
1126     RequirementNotMet {
1127         required_for: &'static str,
1128         requires_one_of: RequiresOneOf,
1129     },
1130 
1131     /// The provided `composite_alpha` is not supported by the surface for this device.
1132     CompositeAlphaNotSupported {
1133         provided: CompositeAlpha,
1134         supported: CompositeAlphas,
1135     },
1136 
1137     /// The provided `format` and `color_space` are not supported by the surface for this device.
1138     FormatColorSpaceNotSupported,
1139 
1140     /// The provided `image_array_layers` is greater than what is supported by the surface for this
1141     /// device.
1142     ImageArrayLayersNotSupported { provided: u32, max_supported: u32 },
1143 
1144     /// The provided `image_extent` is not within the range supported by the surface for this
1145     /// device.
1146     ImageExtentNotSupported {
1147         provided: [u32; 2],
1148         min_supported: [u32; 2],
1149         max_supported: [u32; 2],
1150     },
1151 
1152     /// The provided `image_extent` contained at least one dimension of zero length.
1153     /// This is prohibited by [VUID-VkSwapchainCreateInfoKHR-imageExtent-01689](https://khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSwapchainCreateInfoKHR.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01689)
1154     /// which requires both the width and height be non-zero.
1155     ///
1156     /// This error is distinct from `ImageExtentNotSupported` because a surface's minimum supported
1157     /// length may not enforce this rule.
1158     ImageExtentZeroLengthDimensions,
1159 
1160     /// The provided image parameters are not supported as queried from `image_format_properties`.
1161     ImageFormatPropertiesNotSupported,
1162 
1163     /// The provided `image_sharing` was set to `Concurrent`, but one of the specified queue family
1164     /// indices was out of range.
1165     ImageSharingQueueFamilyIndexOutOfRange {
1166         queue_family_index: u32,
1167         queue_family_count: u32,
1168     },
1169 
1170     /// The provided `image_usage` has fields set that are not supported by the surface for this
1171     /// device.
1172     ImageUsageNotSupported {
1173         provided: ImageUsage,
1174         supported: ImageUsage,
1175     },
1176 
1177     /// The provided `min_image_count` is not within the range supported by the surface for this
1178     /// device.
1179     MinImageCountNotSupported {
1180         provided: u32,
1181         min_supported: u32,
1182         max_supported: Option<u32>,
1183     },
1184 
1185     /// The provided `present_mode` is not supported by the surface for this device.
1186     PresentModeNotSupported,
1187 
1188     /// The provided `pre_transform` is not supported by the surface for this device.
1189     PreTransformNotSupported {
1190         provided: SurfaceTransform,
1191         supported: SurfaceTransforms,
1192     },
1193 
1194     /// The provided `surface` is not supported by any of the device's queue families.
1195     SurfaceNotSupported,
1196 
1197     /// The swapchain has already been used to create a new one.
1198     SwapchainAlreadyRetired,
1199 
1200     /// The `win32_monitor` value was `Some` when it must be `None` or vice-versa.
1201     Win32MonitorInvalid,
1202 }
1203 
1204 impl Error for SwapchainCreationError {
source(&self) -> Option<&(dyn Error + 'static)>1205     fn source(&self) -> Option<&(dyn Error + 'static)> {
1206         match self {
1207             Self::OomError(err) => Some(err),
1208             _ => None,
1209         }
1210     }
1211 }
1212 
1213 impl Display for SwapchainCreationError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1214     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1215         match self {
1216             Self::OomError(_) => write!(f, "not enough memory available"),
1217             Self::DeviceLost => write!(f, "the device was lost"),
1218             Self::SurfaceLost => write!(f, "the surface was lost"),
1219             Self::SurfaceInUse => {
1220                 write!(f, "the surface is already used by another swapchain")
1221             }
1222             Self::NativeWindowInUse => {
1223                 write!(f, "the window is already in use by another API")
1224             }
1225             Self::RequirementNotMet {
1226                 required_for,
1227                 requires_one_of,
1228             } => write!(
1229                 f,
1230                 "a requirement was not met for: {}; requires one of: {}",
1231                 required_for, requires_one_of,
1232             ),
1233             Self::CompositeAlphaNotSupported { .. } => write!(
1234                 f,
1235                 "the provided `composite_alpha` is not supported by the surface for this device",
1236             ),
1237             Self::FormatColorSpaceNotSupported => write!(
1238                 f,
1239                 "the provided `format` and `color_space` are not supported by the surface for this \
1240                 device",
1241             ),
1242             Self::ImageArrayLayersNotSupported {
1243                 provided,
1244                 max_supported,
1245             } => write!(
1246                 f,
1247                 "the provided `image_array_layers` ({}) is greater than what is supported ({}) by \
1248                 the surface for this device",
1249                 provided, max_supported,
1250             ),
1251             Self::ImageExtentNotSupported {
1252                 provided,
1253                 min_supported,
1254                 max_supported,
1255             } => write!(
1256                 f,
1257                 "the provided `image_extent` ({:?}) is not within the range (min: {:?}, max: {:?}) \
1258                 supported by the surface for this device",
1259                 provided, min_supported, max_supported,
1260             ),
1261             Self::ImageExtentZeroLengthDimensions => write!(
1262                 f,
1263                 "the provided `image_extent` contained at least one dimension of zero length",
1264             ),
1265             Self::ImageFormatPropertiesNotSupported => write!(
1266                 f,
1267                 "the provided image parameters are not supported as queried from \
1268                 `image_format_properties`",
1269             ),
1270             Self::ImageSharingQueueFamilyIndexOutOfRange {
1271                 queue_family_index,
1272                 queue_family_count: _,
1273             } => write!(
1274                 f,
1275                 "the provided `image_sharing` was set to `Concurrent`, but one of the specified \
1276                 queue family indices ({}) was out of range",
1277                 queue_family_index,
1278             ),
1279             Self::ImageUsageNotSupported { .. } => write!(
1280                 f,
1281                 "the provided `image_usage` has fields set that are not supported by the surface \
1282                 for this device",
1283             ),
1284             Self::MinImageCountNotSupported {
1285                 provided,
1286                 min_supported,
1287                 max_supported,
1288             } => write!(
1289                 f,
1290                 "the provided `min_image_count` ({}) is not within the range (min: {}, max: {:?}) \
1291                 supported by the surface for this device",
1292                 provided, min_supported, max_supported,
1293             ),
1294             Self::PresentModeNotSupported => write!(
1295                 f,
1296                 "the provided `present_mode` is not supported by the surface for this device",
1297             ),
1298             Self::PreTransformNotSupported { .. } => write!(
1299                 f,
1300                 "the provided `pre_transform` is not supported by the surface for this device",
1301             ),
1302             Self::SurfaceNotSupported => write!(
1303                 f,
1304                 "the provided `surface` is not supported by any of the device's queue families",
1305             ),
1306             Self::SwapchainAlreadyRetired => {
1307                 write!(f, "the swapchain has already been used to create a new one")
1308             }
1309             Self::Win32MonitorInvalid => write!(
1310                 f,
1311                 "the `win32_monitor` value was `Some` when it must be `None` or vice-versa",
1312             ),
1313         }
1314     }
1315 }
1316 
1317 impl From<VulkanError> for SwapchainCreationError {
from(err: VulkanError) -> SwapchainCreationError1318     fn from(err: VulkanError) -> SwapchainCreationError {
1319         match err {
1320             err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
1321             err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
1322             VulkanError::DeviceLost => Self::DeviceLost,
1323             VulkanError::SurfaceLost => Self::SurfaceLost,
1324             VulkanError::NativeWindowInUse => Self::NativeWindowInUse,
1325             _ => panic!("unexpected error: {:?}", err),
1326         }
1327     }
1328 }
1329 
1330 impl From<OomError> for SwapchainCreationError {
from(err: OomError) -> SwapchainCreationError1331     fn from(err: OomError) -> SwapchainCreationError {
1332         Self::OomError(err)
1333     }
1334 }
1335 
1336 impl From<RequirementNotMet> for SwapchainCreationError {
from(err: RequirementNotMet) -> Self1337     fn from(err: RequirementNotMet) -> Self {
1338         Self::RequirementNotMet {
1339             required_for: err.required_for,
1340             requires_one_of: err.requires_one_of,
1341         }
1342     }
1343 }
1344 
1345 vulkan_enum! {
1346     #[non_exhaustive]
1347 
1348     /// The way full-screen exclusivity is handled.
1349     FullScreenExclusive = FullScreenExclusiveEXT(i32);
1350 
1351     /// Indicates that the driver should determine the appropriate full-screen method
1352     /// by whatever means it deems appropriate.
1353     Default = DEFAULT,
1354 
1355     /// Indicates that the driver may use full-screen exclusive mechanisms when available.
1356     /// Such mechanisms may result in better performance and/or the availability of
1357     /// different presentation capabilities, but may require a more disruptive transition
1358     // during swapchain initialization, first presentation and/or destruction.
1359     Allowed = ALLOWED,
1360 
1361     /// Indicates that the driver should avoid using full-screen mechanisms which rely
1362     /// on disruptive transitions.
1363     Disallowed = DISALLOWED,
1364 
1365     /// Indicates the application will manage full-screen exclusive mode by using the
1366     /// [`Swapchain::acquire_full_screen_exclusive()`] and
1367     /// [`Swapchain::release_full_screen_exclusive()`] functions.
1368     ApplicationControlled = APPLICATION_CONTROLLED,
1369 }
1370 
1371 /// A wrapper around a Win32 monitor handle.
1372 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1373 pub struct Win32Monitor(pub(crate) ash::vk::HMONITOR);
1374 
1375 impl Win32Monitor {
1376     /// Wraps a Win32 monitor handle.
1377     ///
1378     /// # Safety
1379     ///
1380     /// - `hmonitor` must be a valid handle as returned by the Win32 API.
new<T>(hmonitor: *const T) -> Self1381     pub unsafe fn new<T>(hmonitor: *const T) -> Self {
1382         Self(hmonitor as _)
1383     }
1384 }
1385 
1386 // Winit's `MonitorHandle` is Send on Win32, so this seems safe.
1387 unsafe impl Send for Win32Monitor {}
1388 unsafe impl Sync for Win32Monitor {}
1389 
1390 /// Error that can happen when calling `Swapchain::acquire_full_screen_exclusive` or
1391 /// `Swapchain::release_full_screen_exclusive`.
1392 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1393 pub enum FullScreenExclusiveError {
1394     /// Not enough memory.
1395     OomError(OomError),
1396 
1397     /// Operation could not be completed for driver specific reasons.
1398     InitializationFailed,
1399 
1400     /// The surface is no longer accessible and must be recreated.
1401     SurfaceLost,
1402 
1403     /// Full-screen exclusivity is already acquired.
1404     DoubleAcquire,
1405 
1406     /// Full-screen exclusivity is not currently acquired.
1407     DoubleRelease,
1408 
1409     /// The swapchain is not in full-screen exclusive application controlled mode.
1410     NotApplicationControlled,
1411 }
1412 
1413 impl Error for FullScreenExclusiveError {
source(&self) -> Option<&(dyn Error + 'static)>1414     fn source(&self) -> Option<&(dyn Error + 'static)> {
1415         match self {
1416             FullScreenExclusiveError::OomError(err) => Some(err),
1417             _ => None,
1418         }
1419     }
1420 }
1421 
1422 impl Display for FullScreenExclusiveError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1423     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1424         write!(
1425             f,
1426             "{}",
1427             match self {
1428                 FullScreenExclusiveError::OomError(_) => "not enough memory",
1429                 FullScreenExclusiveError::SurfaceLost => {
1430                     "the surface of this swapchain is no longer valid"
1431                 }
1432                 FullScreenExclusiveError::InitializationFailed => {
1433                     "operation could not be completed for driver specific reasons"
1434                 }
1435                 FullScreenExclusiveError::DoubleAcquire =>
1436                     "full-screen exclusivity is already acquired",
1437                 FullScreenExclusiveError::DoubleRelease =>
1438                     "full-screen exclusivity is not acquired",
1439                 FullScreenExclusiveError::NotApplicationControlled => {
1440                     "the swapchain is not in full-screen exclusive application controlled mode"
1441                 }
1442             }
1443         )
1444     }
1445 }
1446 
1447 impl From<VulkanError> for FullScreenExclusiveError {
from(err: VulkanError) -> FullScreenExclusiveError1448     fn from(err: VulkanError) -> FullScreenExclusiveError {
1449         match err {
1450             err @ VulkanError::OutOfHostMemory => {
1451                 FullScreenExclusiveError::OomError(OomError::from(err))
1452             }
1453             err @ VulkanError::OutOfDeviceMemory => {
1454                 FullScreenExclusiveError::OomError(OomError::from(err))
1455             }
1456             VulkanError::SurfaceLost => FullScreenExclusiveError::SurfaceLost,
1457             VulkanError::InitializationFailed => FullScreenExclusiveError::InitializationFailed,
1458             _ => panic!("unexpected error: {:?}", err),
1459         }
1460     }
1461 }
1462 
1463 impl From<OomError> for FullScreenExclusiveError {
from(err: OomError) -> FullScreenExclusiveError1464     fn from(err: OomError) -> FullScreenExclusiveError {
1465         FullScreenExclusiveError::OomError(err)
1466     }
1467 }
1468 
1469 /// Tries to take ownership of an image in order to draw on it.
1470 ///
1471 /// The function returns the index of the image in the array of images that was returned
1472 /// when creating the swapchain, plus a future that represents the moment when the image will
1473 /// become available from the GPU (which may not be *immediately*).
1474 ///
1475 /// If you try to draw on an image without acquiring it first, the execution will block. (TODO
1476 /// behavior may change).
1477 ///
1478 /// The second field in the tuple in the Ok result is a bool represent if the acquisition was
1479 /// suboptimal. In this case the acquired image is still usable, but the swapchain should be
1480 /// recreated as the Surface's properties no longer match the swapchain.
acquire_next_image( swapchain: Arc<Swapchain>, timeout: Option<Duration>, ) -> Result<(u32, bool, SwapchainAcquireFuture), AcquireError>1481 pub fn acquire_next_image(
1482     swapchain: Arc<Swapchain>,
1483     timeout: Option<Duration>,
1484 ) -> Result<(u32, bool, SwapchainAcquireFuture), AcquireError> {
1485     let semaphore = Arc::new(Semaphore::from_pool(swapchain.device.clone())?);
1486     let fence = Fence::from_pool(swapchain.device.clone())?;
1487 
1488     let AcquiredImage {
1489         image_index,
1490         suboptimal,
1491     } = {
1492         // Check that this is not an old swapchain. From specs:
1493         // > swapchain must not have been replaced by being passed as the
1494         // > VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR
1495         let retired = swapchain.retired.lock();
1496         if *retired {
1497             return Err(AcquireError::OutOfDate);
1498         }
1499 
1500         let acquire_result =
1501             unsafe { acquire_next_image_raw(&swapchain, timeout, Some(&semaphore), Some(&fence)) };
1502 
1503         if let &Err(AcquireError::FullScreenExclusiveModeLost) = &acquire_result {
1504             swapchain
1505                 .full_screen_exclusive_held
1506                 .store(false, Ordering::SeqCst);
1507         }
1508 
1509         acquire_result?
1510     };
1511 
1512     Ok((
1513         image_index,
1514         suboptimal,
1515         SwapchainAcquireFuture {
1516             swapchain,
1517             semaphore: Some(semaphore),
1518             fence: Some(fence),
1519             image_index,
1520             finished: AtomicBool::new(false),
1521         },
1522     ))
1523 }
1524 
1525 /// Presents an image on the screen.
1526 ///
1527 /// The actual behavior depends on the present mode that you passed when creating the swapchain.
present<F>( before: F, queue: Arc<Queue>, swapchain_info: SwapchainPresentInfo, ) -> PresentFuture<F> where F: GpuFuture,1528 pub fn present<F>(
1529     before: F,
1530     queue: Arc<Queue>,
1531     swapchain_info: SwapchainPresentInfo,
1532 ) -> PresentFuture<F>
1533 where
1534     F: GpuFuture,
1535 {
1536     assert!(swapchain_info.image_index < swapchain_info.swapchain.image_count());
1537 
1538     // TODO: restore this check with a dummy ImageAccess implementation
1539     /*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap();       // TODO: return error instead
1540     // Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
1541     // function on the image instead. But since we know that this method on `SwapchainImage`
1542     // always returns false anyway (by design), we don't need to do it.
1543     assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok());         // TODO: return error instead*/
1544 
1545     PresentFuture {
1546         previous: before,
1547         queue,
1548         swapchain_info,
1549         flushed: AtomicBool::new(false),
1550         finished: AtomicBool::new(false),
1551     }
1552 }
1553 
1554 /// Wait for an image to be presented to the user. Must be used with a `present_id` given to
1555 /// `present_with_id`.
1556 ///
1557 /// Returns a bool to represent if the presentation was suboptimal. In this case the swapchain is
1558 /// still usable, but the swapchain should be recreated as the Surface's properties no longer match
1559 /// the swapchain.
wait_for_present( swapchain: Arc<Swapchain>, present_id: u64, timeout: Option<Duration>, ) -> Result<bool, PresentWaitError>1560 pub fn wait_for_present(
1561     swapchain: Arc<Swapchain>,
1562     present_id: u64,
1563     timeout: Option<Duration>,
1564 ) -> Result<bool, PresentWaitError> {
1565     let retired = swapchain.retired.lock();
1566 
1567     // VUID-vkWaitForPresentKHR-swapchain-04997
1568     if *retired {
1569         return Err(PresentWaitError::OutOfDate);
1570     }
1571 
1572     if present_id == 0 {
1573         return Err(PresentWaitError::PresentIdZero);
1574     }
1575 
1576     // VUID-vkWaitForPresentKHR-presentWait-06234
1577     if !swapchain.device.enabled_features().present_wait {
1578         return Err(PresentWaitError::RequirementNotMet {
1579             required_for: "`wait_for_present`",
1580             requires_one_of: RequiresOneOf {
1581                 features: &["present_wait"],
1582                 ..Default::default()
1583             },
1584         });
1585     }
1586 
1587     let timeout_ns = timeout.map(|dur| dur.as_nanos() as u64).unwrap_or(0);
1588 
1589     let result = unsafe {
1590         (swapchain.device.fns().khr_present_wait.wait_for_present_khr)(
1591             swapchain.device.handle(),
1592             swapchain.handle,
1593             present_id,
1594             timeout_ns,
1595         )
1596     };
1597 
1598     match result {
1599         ash::vk::Result::SUCCESS => Ok(false),
1600         ash::vk::Result::SUBOPTIMAL_KHR => Ok(true),
1601         ash::vk::Result::TIMEOUT => Err(PresentWaitError::Timeout),
1602         err => {
1603             let err = VulkanError::from(err).into();
1604 
1605             if let PresentWaitError::FullScreenExclusiveModeLost = &err {
1606                 swapchain
1607                     .full_screen_exclusive_held
1608                     .store(false, Ordering::SeqCst);
1609             }
1610 
1611             Err(err)
1612         }
1613     }
1614 }
1615 
1616 /// Represents the moment when the GPU will have access to a swapchain image.
1617 #[must_use]
1618 pub struct SwapchainAcquireFuture {
1619     swapchain: Arc<Swapchain>,
1620     image_index: u32,
1621     // Semaphore that is signalled when the acquire is complete. Empty if the acquire has already
1622     // happened.
1623     semaphore: Option<Arc<Semaphore>>,
1624     // Fence that is signalled when the acquire is complete. Empty if the acquire has already
1625     // happened.
1626     fence: Option<Fence>,
1627     finished: AtomicBool,
1628 }
1629 
1630 impl SwapchainAcquireFuture {
1631     /// Returns the index of the image in the list of images returned when creating the swapchain.
image_index(&self) -> u321632     pub fn image_index(&self) -> u32 {
1633         self.image_index
1634     }
1635 
1636     /// Returns the corresponding swapchain.
swapchain(&self) -> &Arc<Swapchain>1637     pub fn swapchain(&self) -> &Arc<Swapchain> {
1638         &self.swapchain
1639     }
1640 
1641     /// Blocks the current thread until the swapchain image has been acquired, or timeout
1642     ///
1643     /// If timeout is `None`, will potentially block forever
1644     ///
1645     /// You still need to join with this future for present to work
wait(&self, timeout: Option<Duration>) -> Result<(), FenceError>1646     pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FenceError> {
1647         match &self.fence {
1648             Some(fence) => fence.wait(timeout),
1649             None => Ok(()),
1650         }
1651     }
1652 }
1653 
1654 unsafe impl GpuFuture for SwapchainAcquireFuture {
cleanup_finished(&mut self)1655     fn cleanup_finished(&mut self) {}
1656 
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>1657     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
1658         if let Some(ref semaphore) = self.semaphore {
1659             let sem = smallvec![semaphore.clone()];
1660             Ok(SubmitAnyBuilder::SemaphoresWait(sem))
1661         } else {
1662             Ok(SubmitAnyBuilder::Empty)
1663         }
1664     }
1665 
flush(&self) -> Result<(), FlushError>1666     fn flush(&self) -> Result<(), FlushError> {
1667         Ok(())
1668     }
1669 
signal_finished(&self)1670     unsafe fn signal_finished(&self) {
1671         self.finished.store(true, Ordering::SeqCst);
1672     }
1673 
queue_change_allowed(&self) -> bool1674     fn queue_change_allowed(&self) -> bool {
1675         true
1676     }
1677 
queue(&self) -> Option<Arc<Queue>>1678     fn queue(&self) -> Option<Arc<Queue>> {
1679         None
1680     }
1681 
check_buffer_access( &self, _buffer: &Buffer, _range: Range<DeviceSize>, _exclusive: bool, _queue: &Queue, ) -> Result<(), AccessCheckError>1682     fn check_buffer_access(
1683         &self,
1684         _buffer: &Buffer,
1685         _range: Range<DeviceSize>,
1686         _exclusive: bool,
1687         _queue: &Queue,
1688     ) -> Result<(), AccessCheckError> {
1689         Err(AccessCheckError::Unknown)
1690     }
1691 
check_image_access( &self, image: &Image, _range: Range<DeviceSize>, _exclusive: bool, expected_layout: ImageLayout, _queue: &Queue, ) -> Result<(), AccessCheckError>1692     fn check_image_access(
1693         &self,
1694         image: &Image,
1695         _range: Range<DeviceSize>,
1696         _exclusive: bool,
1697         expected_layout: ImageLayout,
1698         _queue: &Queue,
1699     ) -> Result<(), AccessCheckError> {
1700         if self.swapchain.index_of_image(image) != Some(self.image_index) {
1701             return Err(AccessCheckError::Unknown);
1702         }
1703 
1704         if !self.swapchain.images[self.image_index as usize]
1705             .layout_initialized
1706             .load(Ordering::Relaxed)
1707             && expected_layout != ImageLayout::Undefined
1708         {
1709             return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
1710                 requested: expected_layout,
1711             }));
1712         }
1713 
1714         if expected_layout != ImageLayout::Undefined && expected_layout != ImageLayout::PresentSrc {
1715             return Err(AccessCheckError::Denied(
1716                 AccessError::UnexpectedImageLayout {
1717                     allowed: ImageLayout::PresentSrc,
1718                     requested: expected_layout,
1719                 },
1720             ));
1721         }
1722 
1723         Ok(())
1724     }
1725 
1726     #[inline]
check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, before: bool, ) -> Result<(), AccessCheckError>1727     fn check_swapchain_image_acquired(
1728         &self,
1729         swapchain: &Swapchain,
1730         image_index: u32,
1731         before: bool,
1732     ) -> Result<(), AccessCheckError> {
1733         if before {
1734             Ok(())
1735         } else {
1736             if swapchain == self.swapchain.as_ref() && image_index == self.image_index {
1737                 Ok(())
1738             } else {
1739                 Err(AccessCheckError::Unknown)
1740             }
1741         }
1742     }
1743 }
1744 
1745 impl Drop for SwapchainAcquireFuture {
drop(&mut self)1746     fn drop(&mut self) {
1747         if thread::panicking() {
1748             return;
1749         }
1750 
1751         if let Some(fence) = &self.fence {
1752             fence.wait(None).unwrap(); // TODO: handle error?
1753             self.semaphore = None;
1754         }
1755 
1756         // TODO: if this future is destroyed without being presented, then eventually acquiring
1757         // a new image will block forever ; difficulty: hard
1758     }
1759 }
1760 
1761 unsafe impl DeviceOwned for SwapchainAcquireFuture {
device(&self) -> &Arc<Device>1762     fn device(&self) -> &Arc<Device> {
1763         &self.swapchain.device
1764     }
1765 }
1766 
1767 /// Error that can happen when calling `acquire_next_image`.
1768 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1769 #[repr(u32)]
1770 pub enum AcquireError {
1771     /// Not enough memory.
1772     OomError(OomError),
1773 
1774     /// The connection to the device has been lost.
1775     DeviceLost,
1776 
1777     /// The timeout of the function has been reached before an image was available.
1778     Timeout,
1779 
1780     /// The surface is no longer accessible and must be recreated.
1781     SurfaceLost,
1782 
1783     /// The swapchain has lost or doesn't have full-screen exclusivity possibly for
1784     /// implementation-specific reasons outside of the application’s control.
1785     FullScreenExclusiveModeLost,
1786 
1787     /// The surface has changed in a way that makes the swapchain unusable. You must query the
1788     /// surface's new properties and recreate a new swapchain if you want to continue drawing.
1789     OutOfDate,
1790 
1791     /// Error during fence creation.
1792     FenceError(FenceError),
1793 
1794     /// Error during semaphore creation.
1795     SemaphoreError(SemaphoreError),
1796 }
1797 
1798 impl Error for AcquireError {
source(&self) -> Option<&(dyn Error + 'static)>1799     fn source(&self) -> Option<&(dyn Error + 'static)> {
1800         match self {
1801             AcquireError::OomError(err) => Some(err),
1802             _ => None,
1803         }
1804     }
1805 }
1806 
1807 impl Display for AcquireError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1808     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1809         write!(
1810             f,
1811             "{}",
1812             match self {
1813                 AcquireError::OomError(_) => "not enough memory",
1814                 AcquireError::DeviceLost => "the connection to the device has been lost",
1815                 AcquireError::Timeout => "no image is available for acquiring yet",
1816                 AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
1817                 AcquireError::OutOfDate => "the swapchain needs to be recreated",
1818                 AcquireError::FullScreenExclusiveModeLost => {
1819                     "the swapchain no longer has full-screen exclusivity"
1820                 }
1821                 AcquireError::FenceError(_) => "error creating fence",
1822                 AcquireError::SemaphoreError(_) => "error creating semaphore",
1823             }
1824         )
1825     }
1826 }
1827 
1828 impl From<FenceError> for AcquireError {
from(err: FenceError) -> Self1829     fn from(err: FenceError) -> Self {
1830         AcquireError::FenceError(err)
1831     }
1832 }
1833 
1834 impl From<SemaphoreError> for AcquireError {
from(err: SemaphoreError) -> Self1835     fn from(err: SemaphoreError) -> Self {
1836         AcquireError::SemaphoreError(err)
1837     }
1838 }
1839 
1840 impl From<OomError> for AcquireError {
from(err: OomError) -> AcquireError1841     fn from(err: OomError) -> AcquireError {
1842         AcquireError::OomError(err)
1843     }
1844 }
1845 
1846 impl From<VulkanError> for AcquireError {
from(err: VulkanError) -> AcquireError1847     fn from(err: VulkanError) -> AcquireError {
1848         match err {
1849             err @ VulkanError::OutOfHostMemory => AcquireError::OomError(OomError::from(err)),
1850             err @ VulkanError::OutOfDeviceMemory => AcquireError::OomError(OomError::from(err)),
1851             VulkanError::DeviceLost => AcquireError::DeviceLost,
1852             VulkanError::SurfaceLost => AcquireError::SurfaceLost,
1853             VulkanError::OutOfDate => AcquireError::OutOfDate,
1854             VulkanError::FullScreenExclusiveModeLost => AcquireError::FullScreenExclusiveModeLost,
1855             _ => panic!("unexpected error: {:?}", err),
1856         }
1857     }
1858 }
1859 
1860 /// Error that can happen when calling `acquire_next_image`.
1861 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1862 #[repr(u32)]
1863 pub enum PresentWaitError {
1864     /// Not enough memory.
1865     OomError(OomError),
1866 
1867     /// The connection to the device has been lost.
1868     DeviceLost,
1869 
1870     /// The surface has changed in a way that makes the swapchain unusable. You must query the
1871     /// surface's new properties and recreate a new swapchain if you want to continue drawing.
1872     OutOfDate,
1873 
1874     /// The surface is no longer accessible and must be recreated.
1875     SurfaceLost,
1876 
1877     /// The swapchain has lost or doesn't have full-screen exclusivity possibly for
1878     /// implementation-specific reasons outside of the application’s control.
1879     FullScreenExclusiveModeLost,
1880 
1881     /// The timeout of the function has been reached before the present occured.
1882     Timeout,
1883 
1884     RequirementNotMet {
1885         required_for: &'static str,
1886         requires_one_of: RequiresOneOf,
1887     },
1888 
1889     /// Present id of zero is invalid.
1890     PresentIdZero,
1891 }
1892 
1893 impl Error for PresentWaitError {
source(&self) -> Option<&(dyn Error + 'static)>1894     fn source(&self) -> Option<&(dyn Error + 'static)> {
1895         match self {
1896             Self::OomError(err) => Some(err),
1897             _ => None,
1898         }
1899     }
1900 }
1901 
1902 impl Display for PresentWaitError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1903     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1904         match self {
1905             Self::OomError(e) => write!(f, "{}", e),
1906             Self::DeviceLost => write!(f, "the connection to the device has been lost"),
1907             Self::Timeout => write!(f, "no image is available for acquiring yet"),
1908             Self::SurfaceLost => write!(f, "the surface of this swapchain is no longer valid"),
1909             Self::OutOfDate => write!(f, "the swapchain needs to be recreated"),
1910             Self::FullScreenExclusiveModeLost => {
1911                 write!(f, "the swapchain no longer has full-screen exclusivity")
1912             }
1913             Self::RequirementNotMet {
1914                 required_for,
1915                 requires_one_of,
1916             } => write!(
1917                 f,
1918                 "a requirement was not met for: {}; requires one of: {}",
1919                 required_for, requires_one_of,
1920             ),
1921             Self::PresentIdZero => write!(f, "present id of zero is invalid"),
1922         }
1923     }
1924 }
1925 
1926 impl From<OomError> for PresentWaitError {
from(err: OomError) -> PresentWaitError1927     fn from(err: OomError) -> PresentWaitError {
1928         Self::OomError(err)
1929     }
1930 }
1931 
1932 impl From<RequirementNotMet> for PresentWaitError {
from(err: RequirementNotMet) -> Self1933     fn from(err: RequirementNotMet) -> Self {
1934         Self::RequirementNotMet {
1935             required_for: err.required_for,
1936             requires_one_of: err.requires_one_of,
1937         }
1938     }
1939 }
1940 
1941 impl From<VulkanError> for PresentWaitError {
from(err: VulkanError) -> PresentWaitError1942     fn from(err: VulkanError) -> PresentWaitError {
1943         match err {
1944             err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
1945             err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
1946             VulkanError::DeviceLost => Self::DeviceLost,
1947             VulkanError::SurfaceLost => Self::SurfaceLost,
1948             VulkanError::OutOfDate => Self::OutOfDate,
1949             VulkanError::FullScreenExclusiveModeLost => Self::FullScreenExclusiveModeLost,
1950             _ => panic!("unexpected error: {:?}", err),
1951         }
1952     }
1953 }
1954 
1955 /// Represents a swapchain image being presented on the screen.
1956 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
1957 pub struct PresentFuture<P>
1958 where
1959     P: GpuFuture,
1960 {
1961     previous: P,
1962     queue: Arc<Queue>,
1963     swapchain_info: SwapchainPresentInfo,
1964     // True if `flush()` has been called on the future, which means that the present command has
1965     // been submitted.
1966     flushed: AtomicBool,
1967     // True if `signal_finished()` has been called on the future, which means that the future has
1968     // been submitted and has already been processed by the GPU.
1969     finished: AtomicBool,
1970 }
1971 
1972 impl<P> PresentFuture<P>
1973 where
1974     P: GpuFuture,
1975 {
1976     /// Returns the index of the image in the list of images returned when creating the swapchain.
image_id(&self) -> u321977     pub fn image_id(&self) -> u32 {
1978         self.swapchain_info.image_index
1979     }
1980 
1981     /// Returns the corresponding swapchain.
swapchain(&self) -> &Arc<Swapchain>1982     pub fn swapchain(&self) -> &Arc<Swapchain> {
1983         &self.swapchain_info.swapchain
1984     }
1985 }
1986 
1987 unsafe impl<P> GpuFuture for PresentFuture<P>
1988 where
1989     P: GpuFuture,
1990 {
cleanup_finished(&mut self)1991     fn cleanup_finished(&mut self) {
1992         self.previous.cleanup_finished();
1993     }
1994 
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>1995     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
1996         if self.flushed.load(Ordering::SeqCst) {
1997             return Ok(SubmitAnyBuilder::Empty);
1998         }
1999 
2000         let mut swapchain_info = self.swapchain_info.clone();
2001         debug_assert!(swapchain_info.image_index < swapchain_info.swapchain.image_count());
2002         let device = swapchain_info.swapchain.device();
2003 
2004         if !device.enabled_features().present_id {
2005             swapchain_info.present_id = None;
2006         }
2007 
2008         if device.enabled_extensions().khr_incremental_present {
2009             for rectangle in &swapchain_info.present_regions {
2010                 assert!(rectangle.is_compatible_with(swapchain_info.swapchain.as_ref()));
2011             }
2012         } else {
2013             swapchain_info.present_regions = Default::default();
2014         }
2015 
2016         let _queue = self.previous.queue();
2017 
2018         // TODO: if the swapchain image layout is not PRESENT, should add a transition command
2019         // buffer
2020 
2021         Ok(match self.previous.build_submission()? {
2022             SubmitAnyBuilder::Empty => SubmitAnyBuilder::QueuePresent(PresentInfo {
2023                 swapchain_infos: vec![self.swapchain_info.clone()],
2024                 ..Default::default()
2025             }),
2026             SubmitAnyBuilder::SemaphoresWait(semaphores) => {
2027                 SubmitAnyBuilder::QueuePresent(PresentInfo {
2028                     wait_semaphores: semaphores.into_iter().collect(),
2029                     swapchain_infos: vec![self.swapchain_info.clone()],
2030                     ..Default::default()
2031                 })
2032             }
2033             SubmitAnyBuilder::CommandBuffer(_, _) => {
2034                 // submit the command buffer by flushing previous.
2035                 // Since the implementation should remember being flushed it's safe to call build_submission multiple times
2036                 self.previous.flush()?;
2037 
2038                 SubmitAnyBuilder::QueuePresent(PresentInfo {
2039                     swapchain_infos: vec![self.swapchain_info.clone()],
2040                     ..Default::default()
2041                 })
2042             }
2043             SubmitAnyBuilder::BindSparse(_, _) => {
2044                 // submit the command buffer by flushing previous.
2045                 // Since the implementation should remember being flushed it's safe to call build_submission multiple times
2046                 self.previous.flush()?;
2047 
2048                 SubmitAnyBuilder::QueuePresent(PresentInfo {
2049                     swapchain_infos: vec![self.swapchain_info.clone()],
2050                     ..Default::default()
2051                 })
2052             }
2053             SubmitAnyBuilder::QueuePresent(mut present_info) => {
2054                 present_info
2055                     .swapchain_infos
2056                     .push(self.swapchain_info.clone());
2057 
2058                 SubmitAnyBuilder::QueuePresent(present_info)
2059             }
2060         })
2061     }
2062 
flush(&self) -> Result<(), FlushError>2063     fn flush(&self) -> Result<(), FlushError> {
2064         unsafe {
2065             // If `flushed` already contains `true`, then `build_submission` will return `Empty`.
2066 
2067             let build_submission_result = self.build_submission();
2068             self.flushed.store(true, Ordering::SeqCst);
2069 
2070             match build_submission_result? {
2071                 SubmitAnyBuilder::Empty => Ok(()),
2072                 SubmitAnyBuilder::QueuePresent(present_info) => {
2073                     // VUID-VkPresentIdKHR-presentIds-04999
2074                     for swapchain_info in &present_info.swapchain_infos {
2075                         if swapchain_info.present_id.map_or(false, |present_id| {
2076                             !swapchain_info.swapchain.try_claim_present_id(present_id)
2077                         }) {
2078                             return Err(FlushError::PresentIdLessThanOrEqual);
2079                         }
2080                     }
2081 
2082                     match self.previous.check_swapchain_image_acquired(
2083                         &self.swapchain_info.swapchain,
2084                         self.swapchain_info.image_index,
2085                         true,
2086                     ) {
2087                         Ok(_) => (),
2088                         Err(AccessCheckError::Unknown) => {
2089                             return Err(AccessError::SwapchainImageNotAcquired.into())
2090                         }
2091                         Err(AccessCheckError::Denied(e)) => return Err(e.into()),
2092                     }
2093 
2094                     Ok(self
2095                         .queue
2096                         .with(|mut q| q.present_unchecked(present_info))?
2097                         .map(|r| r.map(|_| ()))
2098                         .fold(Ok(()), Result::and)?)
2099                 }
2100                 _ => unreachable!(),
2101             }
2102         }
2103     }
2104 
signal_finished(&self)2105     unsafe fn signal_finished(&self) {
2106         self.flushed.store(true, Ordering::SeqCst);
2107         self.finished.store(true, Ordering::SeqCst);
2108         self.previous.signal_finished();
2109     }
2110 
queue_change_allowed(&self) -> bool2111     fn queue_change_allowed(&self) -> bool {
2112         false
2113     }
2114 
queue(&self) -> Option<Arc<Queue>>2115     fn queue(&self) -> Option<Arc<Queue>> {
2116         debug_assert!(match self.previous.queue() {
2117             None => true,
2118             Some(q) => q == self.queue,
2119         });
2120 
2121         Some(self.queue.clone())
2122     }
2123 
check_buffer_access( &self, buffer: &Buffer, range: Range<DeviceSize>, exclusive: bool, queue: &Queue, ) -> Result<(), AccessCheckError>2124     fn check_buffer_access(
2125         &self,
2126         buffer: &Buffer,
2127         range: Range<DeviceSize>,
2128         exclusive: bool,
2129         queue: &Queue,
2130     ) -> Result<(), AccessCheckError> {
2131         self.previous
2132             .check_buffer_access(buffer, range, exclusive, queue)
2133     }
2134 
check_image_access( &self, image: &Image, range: Range<DeviceSize>, exclusive: bool, expected_layout: ImageLayout, queue: &Queue, ) -> Result<(), AccessCheckError>2135     fn check_image_access(
2136         &self,
2137         image: &Image,
2138         range: Range<DeviceSize>,
2139         exclusive: bool,
2140         expected_layout: ImageLayout,
2141         queue: &Queue,
2142     ) -> Result<(), AccessCheckError> {
2143         if self.swapchain_info.swapchain.index_of_image(image)
2144             == Some(self.swapchain_info.image_index)
2145         {
2146             // This future presents the swapchain image, which "unlocks" it. Therefore any attempt
2147             // to use this swapchain image afterwards shouldn't get granted automatic access.
2148             // Instead any attempt to access the image afterwards should get an authorization from
2149             // a later swapchain acquire future. Hence why we return `Unknown` here.
2150             Err(AccessCheckError::Unknown)
2151         } else {
2152             self.previous
2153                 .check_image_access(image, range, exclusive, expected_layout, queue)
2154         }
2155     }
2156 
2157     #[inline]
check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, before: bool, ) -> Result<(), AccessCheckError>2158     fn check_swapchain_image_acquired(
2159         &self,
2160         swapchain: &Swapchain,
2161         image_index: u32,
2162         before: bool,
2163     ) -> Result<(), AccessCheckError> {
2164         if before {
2165             self.previous
2166                 .check_swapchain_image_acquired(swapchain, image_index, false)
2167         } else if swapchain == self.swapchain_info.swapchain.as_ref()
2168             && image_index == self.swapchain_info.image_index
2169         {
2170             Err(AccessError::SwapchainImageNotAcquired.into())
2171         } else {
2172             self.previous
2173                 .check_swapchain_image_acquired(swapchain, image_index, false)
2174         }
2175     }
2176 }
2177 
2178 unsafe impl<P> DeviceOwned for PresentFuture<P>
2179 where
2180     P: GpuFuture,
2181 {
device(&self) -> &Arc<Device>2182     fn device(&self) -> &Arc<Device> {
2183         self.queue.device()
2184     }
2185 }
2186 
2187 impl<P> Drop for PresentFuture<P>
2188 where
2189     P: GpuFuture,
2190 {
drop(&mut self)2191     fn drop(&mut self) {
2192         if thread::panicking() {
2193             return;
2194         }
2195 
2196         unsafe {
2197             if !*self.flushed.get_mut() {
2198                 // Flushing may fail, that's okay. We will still wait for the queue later, so any
2199                 // previous futures that were flushed correctly will still be waited upon.
2200                 self.flush().ok();
2201             }
2202 
2203             if !*self.finished.get_mut() {
2204                 // Block until the queue finished.
2205                 self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
2206                 self.previous.signal_finished();
2207             }
2208         }
2209     }
2210 }
2211 
2212 pub struct AcquiredImage {
2213     pub image_index: u32,
2214     pub suboptimal: bool,
2215 }
2216 
2217 /// Unsafe variant of `acquire_next_image`.
2218 ///
2219 /// # Safety
2220 ///
2221 /// - The semaphore and/or the fence must be kept alive until it is signaled.
2222 /// - The swapchain must not have been replaced by being passed as the old swapchain when creating
2223 ///   a new one.
acquire_next_image_raw( swapchain: &Swapchain, timeout: Option<Duration>, semaphore: Option<&Semaphore>, fence: Option<&Fence>, ) -> Result<AcquiredImage, AcquireError>2224 pub unsafe fn acquire_next_image_raw(
2225     swapchain: &Swapchain,
2226     timeout: Option<Duration>,
2227     semaphore: Option<&Semaphore>,
2228     fence: Option<&Fence>,
2229 ) -> Result<AcquiredImage, AcquireError> {
2230     let fns = swapchain.device.fns();
2231 
2232     let timeout_ns = if let Some(timeout) = timeout {
2233         timeout
2234             .as_secs()
2235             .saturating_mul(1_000_000_000)
2236             .saturating_add(timeout.subsec_nanos() as u64)
2237     } else {
2238         u64::MAX
2239     };
2240 
2241     let mut out = MaybeUninit::uninit();
2242     let result = (fns.khr_swapchain.acquire_next_image_khr)(
2243         swapchain.device.handle(),
2244         swapchain.handle,
2245         timeout_ns,
2246         semaphore
2247             .map(|s| s.handle())
2248             .unwrap_or(ash::vk::Semaphore::null()),
2249         fence.map(|f| f.handle()).unwrap_or(ash::vk::Fence::null()),
2250         out.as_mut_ptr(),
2251     );
2252 
2253     let suboptimal = match result {
2254         ash::vk::Result::SUCCESS => false,
2255         ash::vk::Result::SUBOPTIMAL_KHR => true,
2256         ash::vk::Result::NOT_READY => return Err(AcquireError::Timeout),
2257         ash::vk::Result::TIMEOUT => return Err(AcquireError::Timeout),
2258         err => return Err(VulkanError::from(err).into()),
2259     };
2260 
2261     if let Some(semaphore) = semaphore {
2262         let mut state = semaphore.state();
2263         state.swapchain_acquire();
2264     }
2265 
2266     if let Some(fence) = fence {
2267         let mut state = fence.state();
2268         state.import_swapchain_acquire();
2269     }
2270 
2271     Ok(AcquiredImage {
2272         image_index: out.assume_init(),
2273         suboptimal,
2274     })
2275 }
2276