• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 crate::buffer::BufferAccess;
11 use crate::check_errors;
12 use crate::command_buffer::submit::SubmitAnyBuilder;
13 use crate::command_buffer::submit::SubmitPresentBuilder;
14 use crate::command_buffer::submit::SubmitPresentError;
15 use crate::command_buffer::submit::SubmitSemaphoresWaitBuilder;
16 use crate::device::Device;
17 use crate::device::DeviceOwned;
18 use crate::device::Queue;
19 use crate::format::Format;
20 use crate::image::swapchain::SwapchainImage;
21 use crate::image::sys::UnsafeImage;
22 use crate::image::ImageAccess;
23 use crate::image::ImageCreateFlags;
24 use crate::image::ImageDimensions;
25 use crate::image::ImageInner;
26 use crate::image::ImageLayout;
27 use crate::image::ImageTiling;
28 use crate::image::ImageType;
29 use crate::image::ImageUsage;
30 use crate::image::SampleCount;
31 use crate::swapchain::CapabilitiesError;
32 use crate::swapchain::ColorSpace;
33 use crate::swapchain::CompositeAlpha;
34 use crate::swapchain::PresentMode;
35 use crate::swapchain::PresentRegion;
36 use crate::swapchain::Surface;
37 use crate::swapchain::SurfaceSwapchainLock;
38 use crate::swapchain::SurfaceTransform;
39 use crate::sync::semaphore::SemaphoreError;
40 use crate::sync::AccessCheckError;
41 use crate::sync::AccessError;
42 use crate::sync::AccessFlags;
43 use crate::sync::Fence;
44 use crate::sync::FlushError;
45 use crate::sync::GpuFuture;
46 use crate::sync::PipelineStages;
47 use crate::sync::Semaphore;
48 use crate::sync::SharingMode;
49 use crate::Error;
50 use crate::OomError;
51 use crate::Success;
52 use crate::VulkanObject;
53 use std::error;
54 use std::fmt;
55 use std::mem;
56 use std::mem::MaybeUninit;
57 use std::ptr;
58 use std::sync::atomic::AtomicBool;
59 use std::sync::atomic::Ordering;
60 use std::sync::Arc;
61 use std::sync::Mutex;
62 use std::time::Duration;
63 
64 /// The way fullscreen exclusivity is handled.
65 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
66 #[repr(i32)]
67 pub enum FullscreenExclusive {
68     /// Indicates that the driver should determine the appropriate full-screen method
69     /// by whatever means it deems appropriate.
70     Default = ash::vk::FullScreenExclusiveEXT::DEFAULT.as_raw(),
71     /// Indicates that the driver may use full-screen exclusive mechanisms when available.
72     /// Such mechanisms may result in better performance and/or the availability of
73     /// different presentation capabilities, but may require a more disruptive transition
74     // during swapchain initialization, first presentation and/or destruction.
75     Allowed = ash::vk::FullScreenExclusiveEXT::ALLOWED.as_raw(),
76     /// Indicates that the driver should avoid using full-screen mechanisms which rely
77     /// on disruptive transitions.
78     Disallowed = ash::vk::FullScreenExclusiveEXT::DISALLOWED.as_raw(),
79     /// Indicates the application will manage full-screen exclusive mode by using
80     /// `Swapchain::acquire_fullscreen_exclusive()` and
81     /// `Swapchain::release_fullscreen_exclusive()` functions.
82     AppControlled = ash::vk::FullScreenExclusiveEXT::APPLICATION_CONTROLLED.as_raw(),
83 }
84 
85 impl From<FullscreenExclusive> for ash::vk::FullScreenExclusiveEXT {
86     #[inline]
from(val: FullscreenExclusive) -> Self87     fn from(val: FullscreenExclusive) -> Self {
88         Self::from_raw(val as i32)
89     }
90 }
91 
92 /// Tries to take ownership of an image in order to draw on it.
93 ///
94 /// The function returns the index of the image in the array of images that was returned
95 /// when creating the swapchain, plus a future that represents the moment when the image will
96 /// become available from the GPU (which may not be *immediately*).
97 ///
98 /// If you try to draw on an image without acquiring it first, the execution will block. (TODO
99 /// behavior may change).
100 ///
101 /// The second field in the tuple in the Ok result is a bool represent if the acquisition was
102 /// suboptimal. In this case the acquired image is still usable, but the swapchain should be
103 /// recreated as the Surface's properties no longer match the swapchain.
acquire_next_image<W>( swapchain: Arc<Swapchain<W>>, timeout: Option<Duration>, ) -> Result<(usize, bool, SwapchainAcquireFuture<W>), AcquireError>104 pub fn acquire_next_image<W>(
105     swapchain: Arc<Swapchain<W>>,
106     timeout: Option<Duration>,
107 ) -> Result<(usize, bool, SwapchainAcquireFuture<W>), AcquireError> {
108     let semaphore = Semaphore::from_pool(swapchain.device.clone())?;
109     let fence = Fence::from_pool(swapchain.device.clone())?;
110 
111     let AcquiredImage { id, suboptimal } = {
112         // Check that this is not an old swapchain. From specs:
113         // > swapchain must not have been replaced by being passed as the
114         // > VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR
115         let stale = swapchain.stale.lock().unwrap();
116         if *stale {
117             return Err(AcquireError::OutOfDate);
118         }
119 
120         let acquire_result =
121             unsafe { acquire_next_image_raw(&swapchain, timeout, Some(&semaphore), Some(&fence)) };
122 
123         if let &Err(AcquireError::FullscreenExclusiveLost) = &acquire_result {
124             swapchain
125                 .fullscreen_exclusive_held
126                 .store(false, Ordering::SeqCst);
127         }
128 
129         acquire_result?
130     };
131 
132     Ok((
133         id,
134         suboptimal,
135         SwapchainAcquireFuture {
136             swapchain,
137             semaphore: Some(semaphore),
138             fence: Some(fence),
139             image_id: id,
140             finished: AtomicBool::new(false),
141         },
142     ))
143 }
144 
145 /// Presents an image on the screen.
146 ///
147 /// The parameter is the same index as what `acquire_next_image` returned. The image must
148 /// have been acquired first.
149 ///
150 /// The actual behavior depends on the present mode that you passed when creating the
151 /// swapchain.
present<F, W>( swapchain: Arc<Swapchain<W>>, before: F, queue: Arc<Queue>, index: usize, ) -> PresentFuture<F, W> where F: GpuFuture,152 pub fn present<F, W>(
153     swapchain: Arc<Swapchain<W>>,
154     before: F,
155     queue: Arc<Queue>,
156     index: usize,
157 ) -> PresentFuture<F, W>
158 where
159     F: GpuFuture,
160 {
161     assert!(index < swapchain.images.len());
162 
163     // TODO: restore this check with a dummy ImageAccess implementation
164     /*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap();       // TODO: return error instead
165     // Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
166     // function on the image instead. But since we know that this method on `SwapchainImage`
167     // always returns false anyway (by design), we don't need to do it.
168     assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok());         // TODO: return error instead*/
169 
170     PresentFuture {
171         previous: before,
172         queue,
173         swapchain,
174         image_id: index,
175         present_region: None,
176         flushed: AtomicBool::new(false),
177         finished: AtomicBool::new(false),
178     }
179 }
180 
181 /// Same as `swapchain::present`, except it allows specifying a present region.
182 /// Areas outside the present region may be ignored by Vulkan in order to optimize presentation.
183 ///
184 /// This is just an optimization hint, as the Vulkan driver is free to ignore the given present region.
185 ///
186 /// If `VK_KHR_incremental_present` is not enabled on the device, the parameter will be ignored.
present_incremental<F, W>( swapchain: Arc<Swapchain<W>>, before: F, queue: Arc<Queue>, index: usize, present_region: PresentRegion, ) -> PresentFuture<F, W> where F: GpuFuture,187 pub fn present_incremental<F, W>(
188     swapchain: Arc<Swapchain<W>>,
189     before: F,
190     queue: Arc<Queue>,
191     index: usize,
192     present_region: PresentRegion,
193 ) -> PresentFuture<F, W>
194 where
195     F: GpuFuture,
196 {
197     assert!(index < swapchain.images.len());
198 
199     // TODO: restore this check with a dummy ImageAccess implementation
200     /*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap();       // TODO: return error instead
201     // Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
202     // function on the image instead. But since we know that this method on `SwapchainImage`
203     // always returns false anyway (by design), we don't need to do it.
204     assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok());         // TODO: return error instead*/
205 
206     PresentFuture {
207         previous: before,
208         queue,
209         swapchain,
210         image_id: index,
211         present_region: Some(present_region),
212         flushed: AtomicBool::new(false),
213         finished: AtomicBool::new(false),
214     }
215 }
216 
217 /// Contains the swapping system and the images that can be shown on a surface.
218 pub struct Swapchain<W> {
219     // The Vulkan device this swapchain was created with.
220     device: Arc<Device>,
221     // The surface, which we need to keep alive.
222     surface: Arc<Surface<W>>,
223     // The swapchain object.
224     swapchain: ash::vk::SwapchainKHR,
225 
226     // The images of this swapchain.
227     images: Vec<ImageEntry>,
228 
229     // If true, that means we have tried to use this swapchain to recreate a new swapchain. The current
230     // swapchain can no longer be used for anything except presenting already-acquired images.
231     //
232     // We use a `Mutex` instead of an `AtomicBool` because we want to keep that locked while
233     // we acquire the image.
234     stale: Mutex<bool>,
235 
236     // Parameters passed to the constructor.
237     num_images: u32,
238     format: Format,
239     color_space: ColorSpace,
240     dimensions: [u32; 2],
241     layers: u32,
242     usage: ImageUsage,
243     sharing_mode: SharingMode,
244     transform: SurfaceTransform,
245     composite_alpha: CompositeAlpha,
246     present_mode: PresentMode,
247     fullscreen_exclusive: FullscreenExclusive,
248     fullscreen_exclusive_held: AtomicBool,
249     clipped: bool,
250 }
251 
252 struct ImageEntry {
253     // The actual image.
254     image: UnsafeImage,
255     // If true, then the image is still in the undefined layout and must be transitioned.
256     undefined_layout: AtomicBool,
257 }
258 
259 impl<W> Swapchain<W> {
260     /// Starts the process of building a new swapchain, using default values for the parameters.
261     #[inline]
start(device: Arc<Device>, surface: Arc<Surface<W>>) -> SwapchainBuilder<W>262     pub fn start(device: Arc<Device>, surface: Arc<Surface<W>>) -> SwapchainBuilder<W> {
263         SwapchainBuilder {
264             device,
265             surface,
266 
267             num_images: 2,
268             format: None,
269             color_space: ColorSpace::SrgbNonLinear,
270             dimensions: None,
271             layers: 1,
272             usage: ImageUsage::none(),
273             sharing_mode: SharingMode::Exclusive,
274             transform: Default::default(),
275             composite_alpha: CompositeAlpha::Opaque,
276             present_mode: PresentMode::Fifo,
277             fullscreen_exclusive: FullscreenExclusive::Default,
278             clipped: true,
279 
280             old_swapchain: None,
281         }
282     }
283 
284     /// Starts building a new swapchain from an existing swapchain.
285     ///
286     /// Use this when a swapchain has become invalidated, such as due to window resizes.
287     /// The builder is pre-filled with the parameters of the old one, except for `dimensions`,
288     /// which is set to `None`.
289     #[inline]
recreate(self: &Arc<Self>) -> SwapchainBuilder<W>290     pub fn recreate(self: &Arc<Self>) -> SwapchainBuilder<W> {
291         SwapchainBuilder {
292             device: self.device().clone(),
293             surface: self.surface().clone(),
294 
295             num_images: self.images.len() as u32,
296             format: Some(self.format),
297             color_space: self.color_space,
298             dimensions: None,
299             layers: self.layers,
300             usage: self.usage,
301             sharing_mode: self.sharing_mode.clone(),
302             transform: self.transform,
303             composite_alpha: self.composite_alpha,
304             present_mode: self.present_mode,
305             fullscreen_exclusive: self.fullscreen_exclusive,
306             clipped: self.clipped,
307 
308             old_swapchain: Some(self.clone()),
309         }
310     }
311 
312     /// Returns the saved Surface, from the Swapchain creation.
313     #[inline]
surface(&self) -> &Arc<Surface<W>>314     pub fn surface(&self) -> &Arc<Surface<W>> {
315         &self.surface
316     }
317 
318     /// Returns of the images that belong to this swapchain.
319     #[inline]
raw_image(&self, offset: usize) -> Option<ImageInner>320     pub fn raw_image(&self, offset: usize) -> Option<ImageInner> {
321         self.images.get(offset).map(|i| ImageInner {
322             image: &i.image,
323             first_layer: 0,
324             num_layers: self.layers as usize,
325             first_mipmap_level: 0,
326             num_mipmap_levels: 1,
327         })
328     }
329 
330     /// Returns the number of images of the swapchain.
331     #[inline]
num_images(&self) -> u32332     pub fn num_images(&self) -> u32 {
333         self.images.len() as u32
334     }
335 
336     /// Returns the format of the images of the swapchain.
337     #[inline]
format(&self) -> Format338     pub fn format(&self) -> Format {
339         self.format
340     }
341 
342     /// Returns the dimensions of the images of the swapchain.
343     #[inline]
dimensions(&self) -> [u32; 2]344     pub fn dimensions(&self) -> [u32; 2] {
345         self.dimensions
346     }
347 
348     /// Returns the number of layers of the images of the swapchain.
349     #[inline]
layers(&self) -> u32350     pub fn layers(&self) -> u32 {
351         self.layers
352     }
353 
354     /// Returns the transform that was passed when creating the swapchain.
355     #[inline]
transform(&self) -> SurfaceTransform356     pub fn transform(&self) -> SurfaceTransform {
357         self.transform
358     }
359 
360     /// Returns the alpha mode that was passed when creating the swapchain.
361     #[inline]
composite_alpha(&self) -> CompositeAlpha362     pub fn composite_alpha(&self) -> CompositeAlpha {
363         self.composite_alpha
364     }
365 
366     /// Returns the present mode that was passed when creating the swapchain.
367     #[inline]
present_mode(&self) -> PresentMode368     pub fn present_mode(&self) -> PresentMode {
369         self.present_mode
370     }
371 
372     /// Returns the value of `clipped` that was passed when creating the swapchain.
373     #[inline]
clipped(&self) -> bool374     pub fn clipped(&self) -> bool {
375         self.clipped
376     }
377 
378     /// Returns the value of 'fullscreen_exclusive` that was passed when creating the swapchain.
379     #[inline]
fullscreen_exclusive(&self) -> FullscreenExclusive380     pub fn fullscreen_exclusive(&self) -> FullscreenExclusive {
381         self.fullscreen_exclusive
382     }
383 
384     /// `FullscreenExclusive::AppControlled` must be the active fullscreen exclusivity mode.
385     /// Acquire fullscreen exclusivity until either the `release_fullscreen_exclusive` is
386     /// called, or if any of the the other `Swapchain` functions return `FullscreenExclusiveLost`.
387     /// Requires: `FullscreenExclusive::AppControlled`
acquire_fullscreen_exclusive(&self) -> Result<(), FullscreenExclusiveError>388     pub fn acquire_fullscreen_exclusive(&self) -> Result<(), FullscreenExclusiveError> {
389         if self.fullscreen_exclusive != FullscreenExclusive::AppControlled {
390             return Err(FullscreenExclusiveError::NotAppControlled);
391         }
392 
393         if self.fullscreen_exclusive_held.swap(true, Ordering::SeqCst) {
394             return Err(FullscreenExclusiveError::DoubleAcquire);
395         }
396 
397         unsafe {
398             check_errors(
399                 self.device
400                     .fns()
401                     .ext_full_screen_exclusive
402                     .acquire_full_screen_exclusive_mode_ext(
403                         self.device.internal_object(),
404                         self.swapchain,
405                     ),
406             )?;
407         }
408 
409         Ok(())
410     }
411 
412     /// `FullscreenExclusive::AppControlled` must be the active fullscreen exclusivity mode.
413     /// Release fullscreen exclusivity.
release_fullscreen_exclusive(&self) -> Result<(), FullscreenExclusiveError>414     pub fn release_fullscreen_exclusive(&self) -> Result<(), FullscreenExclusiveError> {
415         if self.fullscreen_exclusive != FullscreenExclusive::AppControlled {
416             return Err(FullscreenExclusiveError::NotAppControlled);
417         }
418 
419         if !self.fullscreen_exclusive_held.swap(false, Ordering::SeqCst) {
420             return Err(FullscreenExclusiveError::DoubleRelease);
421         }
422 
423         unsafe {
424             check_errors(
425                 self.device
426                     .fns()
427                     .ext_full_screen_exclusive
428                     .release_full_screen_exclusive_mode_ext(
429                         self.device.internal_object(),
430                         self.swapchain,
431                     ),
432             )?;
433         }
434 
435         Ok(())
436     }
437 
438     /// `FullscreenExclusive::AppControlled` is not the active fullscreen exclusivity mode,
439     /// then this function will always return false. If true is returned the swapchain
440     /// is in `FullscreenExclusive::AppControlled` fullscreen exclusivity mode and exclusivity
441     /// is currently acquired.
is_fullscreen_exclusive(&self) -> bool442     pub fn is_fullscreen_exclusive(&self) -> bool {
443         if self.fullscreen_exclusive != FullscreenExclusive::AppControlled {
444             false
445         } else {
446             self.fullscreen_exclusive_held.load(Ordering::SeqCst)
447         }
448     }
449 
450     // This method is necessary to allow `SwapchainImage`s to signal when they have been
451     // transitioned out of their initial `undefined` image layout.
452     //
453     // See the `ImageAccess::layout_initialized` method documentation for more details.
image_layout_initialized(&self, image_offset: usize)454     pub(crate) fn image_layout_initialized(&self, image_offset: usize) {
455         let image_entry = self.images.get(image_offset);
456         if let Some(ref image_entry) = image_entry {
457             image_entry.undefined_layout.store(false, Ordering::SeqCst);
458         }
459     }
460 
is_image_layout_initialized(&self, image_offset: usize) -> bool461     pub(crate) fn is_image_layout_initialized(&self, image_offset: usize) -> bool {
462         let image_entry = self.images.get(image_offset);
463         if let Some(ref image_entry) = image_entry {
464             !image_entry.undefined_layout.load(Ordering::SeqCst)
465         } else {
466             false
467         }
468     }
469 }
470 
471 unsafe impl<W> VulkanObject for Swapchain<W> {
472     type Object = ash::vk::SwapchainKHR;
473 
474     #[inline]
internal_object(&self) -> ash::vk::SwapchainKHR475     fn internal_object(&self) -> ash::vk::SwapchainKHR {
476         self.swapchain
477     }
478 }
479 
480 unsafe impl<W> DeviceOwned for Swapchain<W> {
device(&self) -> &Arc<Device>481     fn device(&self) -> &Arc<Device> {
482         &self.device
483     }
484 }
485 
486 impl<W> fmt::Debug for Swapchain<W> {
487     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>488     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
489         write!(fmt, "<Vulkan swapchain {:?}>", self.swapchain)
490     }
491 }
492 
493 impl<W> Drop for Swapchain<W> {
494     #[inline]
drop(&mut self)495     fn drop(&mut self) {
496         unsafe {
497             let fns = self.device.fns();
498             fns.khr_swapchain.destroy_swapchain_khr(
499                 self.device.internal_object(),
500                 self.swapchain,
501                 ptr::null(),
502             );
503             self.surface.flag().store(false, Ordering::Release);
504         }
505     }
506 }
507 
508 /// Builder for a [`Swapchain`].
509 #[derive(Debug)]
510 pub struct SwapchainBuilder<W> {
511     device: Arc<Device>,
512     surface: Arc<Surface<W>>,
513     old_swapchain: Option<Arc<Swapchain<W>>>,
514 
515     num_images: u32,
516     format: Option<Format>, // None = use a default
517     color_space: ColorSpace,
518     dimensions: Option<[u32; 2]>,
519     layers: u32,
520     usage: ImageUsage,
521     sharing_mode: SharingMode,
522     transform: SurfaceTransform,
523     composite_alpha: CompositeAlpha,
524     present_mode: PresentMode,
525     fullscreen_exclusive: FullscreenExclusive,
526     clipped: bool,
527 }
528 
529 impl<W> SwapchainBuilder<W> {
530     /// Builds a new swapchain. Allocates images who content can be made visible on a surface.
531     ///
532     /// See also the `Surface::get_capabilities` function which returns the values that are
533     /// supported by the implementation. All the parameters that you pass to the builder
534     /// must be supported.
535     ///
536     /// This function returns the swapchain plus a list of the images that belong to the
537     /// swapchain. The order in which the images are returned is important for the
538     /// `acquire_next_image` and `present` functions.
539     ///
540     /// # Panic
541     ///
542     /// - Panics if the device and the surface don't belong to the same instance.
543     /// - Panics if `usage` is empty.
544     ///
545     // TODO: isn't it unsafe to take the surface through an Arc when it comes to vulkano-win?
build( self, ) -> Result<(Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>), SwapchainCreationError>546     pub fn build(
547         self,
548     ) -> Result<(Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>), SwapchainCreationError> {
549         let SwapchainBuilder {
550             device,
551             surface,
552             old_swapchain,
553 
554             num_images,
555             format,
556             color_space,
557             dimensions,
558             layers,
559             usage,
560             sharing_mode,
561             transform,
562             composite_alpha,
563             present_mode,
564             fullscreen_exclusive,
565             clipped,
566         } = self;
567 
568         assert_eq!(
569             device.instance().internal_object(),
570             surface.instance().internal_object()
571         );
572 
573         // Checking that the requested parameters match the capabilities.
574         let capabilities = surface.capabilities(device.physical_device())?;
575         if num_images < capabilities.min_image_count {
576             return Err(SwapchainCreationError::UnsupportedMinImagesCount);
577         }
578         if let Some(c) = capabilities.max_image_count {
579             if num_images > c {
580                 return Err(SwapchainCreationError::UnsupportedMaxImagesCount);
581             }
582         }
583 
584         let format = {
585             if let Some(format) = format {
586                 if !capabilities
587                     .supported_formats
588                     .iter()
589                     .any(|&(f, c)| f == format && c == color_space)
590                 {
591                     return Err(SwapchainCreationError::UnsupportedFormat);
592                 }
593                 format
594             } else {
595                 if let Some(format) = [Format::R8G8B8A8Unorm, Format::B8G8R8A8Unorm]
596                     .iter()
597                     .copied()
598                     .find(|&format| {
599                         capabilities
600                             .supported_formats
601                             .iter()
602                             .any(|&(f, c)| f == format && c == color_space)
603                     })
604                 {
605                     format
606                 } else {
607                     return Err(SwapchainCreationError::UnsupportedFormat);
608                 }
609             }
610         };
611 
612         let dimensions = if let Some(dimensions) = dimensions {
613             if dimensions[0] < capabilities.min_image_extent[0] {
614                 return Err(SwapchainCreationError::UnsupportedDimensions);
615             }
616             if dimensions[1] < capabilities.min_image_extent[1] {
617                 return Err(SwapchainCreationError::UnsupportedDimensions);
618             }
619             if dimensions[0] > capabilities.max_image_extent[0] {
620                 return Err(SwapchainCreationError::UnsupportedDimensions);
621             }
622             if dimensions[1] > capabilities.max_image_extent[1] {
623                 return Err(SwapchainCreationError::UnsupportedDimensions);
624             }
625             dimensions
626         } else {
627             capabilities.current_extent.unwrap()
628         };
629         if layers < 1 || layers > capabilities.max_image_array_layers {
630             return Err(SwapchainCreationError::UnsupportedArrayLayers);
631         }
632         if (ash::vk::ImageUsageFlags::from(usage)
633             & ash::vk::ImageUsageFlags::from(capabilities.supported_usage_flags))
634             != ash::vk::ImageUsageFlags::from(usage)
635         {
636             return Err(SwapchainCreationError::UnsupportedUsageFlags);
637         }
638         if !capabilities.supported_transforms.supports(transform) {
639             return Err(SwapchainCreationError::UnsupportedSurfaceTransform);
640         }
641         if !capabilities
642             .supported_composite_alpha
643             .supports(composite_alpha)
644         {
645             return Err(SwapchainCreationError::UnsupportedCompositeAlpha);
646         }
647         if !capabilities.present_modes.supports(present_mode) {
648             return Err(SwapchainCreationError::UnsupportedPresentMode);
649         }
650 
651         let flags = ImageCreateFlags::none();
652 
653         // check that the physical device supports the swapchain image configuration
654         match device.image_format_properties(
655             format,
656             ImageType::Dim2d,
657             ImageTiling::Optimal,
658             usage,
659             flags,
660         ) {
661             Ok(_) => (),
662             Err(e) => {
663                 eprintln!("{}", e);
664                 return Err(SwapchainCreationError::UnsupportedImageConfiguration);
665             }
666         }
667 
668         // If we recreate a swapchain, make sure that the surface is the same.
669         if let Some(ref sc) = old_swapchain {
670             if surface.internal_object() != sc.surface.internal_object() {
671                 return Err(SwapchainCreationError::OldSwapchainSurfaceMismatch);
672             }
673         } else {
674             // Checking that the surface doesn't already have a swapchain.
675             let has_already = surface.flag().swap(true, Ordering::AcqRel);
676             if has_already {
677                 return Err(SwapchainCreationError::SurfaceInUse);
678             }
679         }
680 
681         if !device.enabled_extensions().khr_swapchain {
682             return Err(SwapchainCreationError::MissingExtensionKHRSwapchain);
683         }
684 
685         let mut surface_full_screen_exclusive_info = None;
686 
687         // TODO: VK_EXT_FULL_SCREEN_EXCLUSIVE requires these extensions, so they should always
688         // be enabled if it is. A separate check here is unnecessary; this should be checked at
689         // device creation.
690         if device.enabled_extensions().ext_full_screen_exclusive
691             && surface
692                 .instance()
693                 .enabled_extensions()
694                 .khr_get_physical_device_properties2
695             && surface
696                 .instance()
697                 .enabled_extensions()
698                 .khr_get_surface_capabilities2
699         {
700             surface_full_screen_exclusive_info = Some(ash::vk::SurfaceFullScreenExclusiveInfoEXT {
701                 full_screen_exclusive: fullscreen_exclusive.into(),
702                 ..Default::default()
703             });
704         }
705 
706         let p_next = match surface_full_screen_exclusive_info.as_ref() {
707             Some(some) => unsafe { mem::transmute(some as *const _) },
708             None => ptr::null(),
709         };
710 
711         // Required by the specs.
712         assert_ne!(usage, ImageUsage::none());
713 
714         if let Some(ref old_swapchain) = old_swapchain {
715             let mut stale = old_swapchain.stale.lock().unwrap();
716 
717             // The swapchain has already been used to create a new one.
718             if *stale {
719                 return Err(SwapchainCreationError::OldSwapchainAlreadyUsed);
720             } else {
721                 // According to the documentation of VkSwapchainCreateInfoKHR:
722                 //
723                 // > Upon calling vkCreateSwapchainKHR with a oldSwapchain that is not VK_NULL_HANDLE,
724                 // > any images not acquired by the application may be freed by the implementation,
725                 // > which may occur even if creation of the new swapchain fails.
726                 //
727                 // Therefore, we set stale to true and keep it to true even if the call to `vkCreateSwapchainKHR` below fails.
728                 *stale = true;
729             }
730         }
731 
732         let fns = device.fns();
733 
734         let swapchain = unsafe {
735             let (sh_mode, sh_count, sh_indices) = match sharing_mode {
736                 SharingMode::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, 0, ptr::null()),
737                 SharingMode::Concurrent(ref ids) => (
738                     ash::vk::SharingMode::CONCURRENT,
739                     ids.len() as u32,
740                     ids.as_ptr(),
741                 ),
742             };
743 
744             let infos = ash::vk::SwapchainCreateInfoKHR {
745                 p_next,
746                 flags: ash::vk::SwapchainCreateFlagsKHR::empty(),
747                 surface: surface.internal_object(),
748                 min_image_count: num_images,
749                 image_format: format.into(),
750                 image_color_space: color_space.into(),
751                 image_extent: ash::vk::Extent2D {
752                     width: dimensions[0],
753                     height: dimensions[1],
754                 },
755                 image_array_layers: layers,
756                 image_usage: usage.into(),
757                 image_sharing_mode: sh_mode,
758                 queue_family_index_count: sh_count,
759                 p_queue_family_indices: sh_indices,
760                 pre_transform: transform.into(),
761                 composite_alpha: composite_alpha.into(),
762                 present_mode: present_mode.into(),
763                 clipped: if clipped {
764                     ash::vk::TRUE
765                 } else {
766                     ash::vk::FALSE
767                 },
768                 old_swapchain: if let Some(ref old_swapchain) = old_swapchain {
769                     old_swapchain.swapchain
770                 } else {
771                     ash::vk::SwapchainKHR::null()
772                 },
773                 ..Default::default()
774             };
775 
776             let mut output = MaybeUninit::uninit();
777             check_errors(fns.khr_swapchain.create_swapchain_khr(
778                 device.internal_object(),
779                 &infos,
780                 ptr::null(),
781                 output.as_mut_ptr(),
782             ))?;
783             output.assume_init()
784         };
785 
786         let image_handles = unsafe {
787             let mut num = 0;
788             check_errors(fns.khr_swapchain.get_swapchain_images_khr(
789                 device.internal_object(),
790                 swapchain,
791                 &mut num,
792                 ptr::null_mut(),
793             ))?;
794 
795             let mut images = Vec::with_capacity(num as usize);
796             check_errors(fns.khr_swapchain.get_swapchain_images_khr(
797                 device.internal_object(),
798                 swapchain,
799                 &mut num,
800                 images.as_mut_ptr(),
801             ))?;
802             images.set_len(num as usize);
803             images
804         };
805 
806         let images = image_handles
807             .into_iter()
808             .map(|image| unsafe {
809                 let dims = ImageDimensions::Dim2d {
810                     width: dimensions[0],
811                     height: dimensions[1],
812                     array_layers: layers,
813                 };
814 
815                 let img = UnsafeImage::from_raw(
816                     device.clone(),
817                     image,
818                     usage,
819                     format,
820                     flags,
821                     dims,
822                     SampleCount::Sample1,
823                     1,
824                 );
825 
826                 ImageEntry {
827                     image: img,
828                     undefined_layout: AtomicBool::new(true),
829                 }
830             })
831             .collect::<Vec<_>>();
832 
833         let fullscreen_exclusive_held = old_swapchain
834             .as_ref()
835             .map(|old_swapchain| {
836                 if old_swapchain.fullscreen_exclusive != FullscreenExclusive::AppControlled {
837                     false
838                 } else {
839                     old_swapchain
840                         .fullscreen_exclusive_held
841                         .load(Ordering::SeqCst)
842                 }
843             })
844             .unwrap_or(false);
845 
846         let swapchain = Arc::new(Swapchain {
847             device: device.clone(),
848             surface: surface.clone(),
849             swapchain,
850             images,
851             stale: Mutex::new(false),
852             num_images,
853             format,
854             color_space,
855             dimensions,
856             layers,
857             usage: usage.clone(),
858             sharing_mode,
859             transform,
860             composite_alpha,
861             present_mode,
862             fullscreen_exclusive,
863             fullscreen_exclusive_held: AtomicBool::new(fullscreen_exclusive_held),
864             clipped,
865         });
866 
867         let swapchain_images = unsafe {
868             let mut swapchain_images = Vec::with_capacity(swapchain.images.len());
869             for n in 0..swapchain.images.len() {
870                 swapchain_images.push(SwapchainImage::from_raw(swapchain.clone(), n)?);
871             }
872             swapchain_images
873         };
874 
875         Ok((swapchain, swapchain_images))
876     }
877 
878     /// Sets the number of images that will be created.
879     ///
880     /// The default is 2.
881     #[inline]
num_images(mut self, num_images: u32) -> Self882     pub fn num_images(mut self, num_images: u32) -> Self {
883         self.num_images = num_images;
884         self
885     }
886 
887     /// Sets the pixel format that will be used for the images.
888     ///
889     /// The default is either `R8G8B8A8Unorm` or `B8G8R8A8Unorm`, whichever is supported.
890     #[inline]
format(mut self, format: Format) -> Self891     pub fn format(mut self, format: Format) -> Self {
892         self.format = Some(format);
893         self
894     }
895 
896     /// Sets the color space that will be used for the images.
897     ///
898     /// The default is `SrgbNonLinear`.
899     #[inline]
color_space(mut self, color_space: ColorSpace) -> Self900     pub fn color_space(mut self, color_space: ColorSpace) -> Self {
901         self.color_space = color_space;
902         self
903     }
904 
905     /// Sets the dimensions of the images.
906     ///
907     /// The default is `None`, which means the value of
908     /// [`Capabilities::current_extent`](crate::swapchain::Capabilities::current_extent) will be
909     /// used. Setting this will override it with a custom `Some` value.
910     #[inline]
dimensions(mut self, dimensions: [u32; 2]) -> Self911     pub fn dimensions(mut self, dimensions: [u32; 2]) -> Self {
912         self.dimensions = Some(dimensions);
913         self
914     }
915 
916     /// Sets the number of layers for each image.
917     ///
918     /// The default is 1.
919     #[inline]
layers(mut self, layers: u32) -> Self920     pub fn layers(mut self, layers: u32) -> Self {
921         self.layers = layers;
922         self
923     }
924 
925     /// Sets how the images will be used.
926     ///
927     /// The default is `ImageUsage::none()`.
928     #[inline]
usage(mut self, usage: ImageUsage) -> Self929     pub fn usage(mut self, usage: ImageUsage) -> Self {
930         self.usage = usage;
931         self
932     }
933 
934     /// Sets the sharing mode of the images.
935     ///
936     /// The default is `Exclusive`.
937     #[inline]
sharing_mode<S>(mut self, sharing_mode: S) -> Self where S: Into<SharingMode>,938     pub fn sharing_mode<S>(mut self, sharing_mode: S) -> Self
939     where
940         S: Into<SharingMode>,
941     {
942         self.sharing_mode = sharing_mode.into();
943         self
944     }
945 
946     /// Sets the transform that is to be applied to the surface.
947     ///
948     /// The default is `Identity`.
949     #[inline]
transform(mut self, transform: SurfaceTransform) -> Self950     pub fn transform(mut self, transform: SurfaceTransform) -> Self {
951         self.transform = transform;
952         self
953     }
954 
955     /// Sets how alpha values of the pixels in the image are to be treated.
956     ///
957     /// The default is `Opaque`.
958     #[inline]
composite_alpha(mut self, composite_alpha: CompositeAlpha) -> Self959     pub fn composite_alpha(mut self, composite_alpha: CompositeAlpha) -> Self {
960         self.composite_alpha = composite_alpha;
961         self
962     }
963 
964     /// Sets the present mode for the swapchain.
965     ///
966     /// The default is `Fifo`.
967     #[inline]
present_mode(mut self, present_mode: PresentMode) -> Self968     pub fn present_mode(mut self, present_mode: PresentMode) -> Self {
969         self.present_mode = present_mode;
970         self
971     }
972 
973     /// Sets how fullscreen exclusivity is to be handled.
974     ///
975     /// The default is `Default`.
976     #[inline]
fullscreen_exclusive(mut self, fullscreen_exclusive: FullscreenExclusive) -> Self977     pub fn fullscreen_exclusive(mut self, fullscreen_exclusive: FullscreenExclusive) -> Self {
978         self.fullscreen_exclusive = fullscreen_exclusive;
979         self
980     }
981 
982     /// Sets whether the implementation is allowed to discard rendering operations that affect
983     /// regions of the surface which aren't visible. This is important to take into account if
984     /// your fragment shader has side-effects or if you want to read back the content of the image
985     /// afterwards.
986     ///
987     /// The default is `true`.
988     #[inline]
clipped(mut self, clipped: bool) -> Self989     pub fn clipped(mut self, clipped: bool) -> Self {
990         self.clipped = clipped;
991         self
992     }
993 }
994 
995 /// Error that can happen when creation a swapchain.
996 #[derive(Clone, Debug, PartialEq, Eq)]
997 pub enum SwapchainCreationError {
998     /// Not enough memory.
999     OomError(OomError),
1000     /// The device was lost.
1001     DeviceLost,
1002     /// The surface was lost.
1003     SurfaceLost,
1004     /// The surface is already used by another swapchain.
1005     SurfaceInUse,
1006     /// The window is already in use by another API.
1007     NativeWindowInUse,
1008     /// The `VK_KHR_swapchain` extension was not enabled.
1009     MissingExtensionKHRSwapchain,
1010     /// The `VK_EXT_full_screen_exclusive` extension was not enabled.
1011     MissingExtensionExtFullScreenExclusive,
1012     /// Surface mismatch between old and new swapchain.
1013     OldSwapchainSurfaceMismatch,
1014     /// The old swapchain has already been used to recreate another one.
1015     OldSwapchainAlreadyUsed,
1016     /// The requested number of swapchain images is not supported by the surface.
1017     UnsupportedMinImagesCount,
1018     /// The requested number of swapchain images is not supported by the surface.
1019     UnsupportedMaxImagesCount,
1020     /// The requested image format is not supported by the surface.
1021     UnsupportedFormat,
1022     /// The requested dimensions are not supported by the surface.
1023     UnsupportedDimensions,
1024     /// The requested array layers count is not supported by the surface.
1025     UnsupportedArrayLayers,
1026     /// The requested image usage is not supported by the surface.
1027     UnsupportedUsageFlags,
1028     /// The requested surface transform is not supported by the surface.
1029     UnsupportedSurfaceTransform,
1030     /// The requested composite alpha is not supported by the surface.
1031     UnsupportedCompositeAlpha,
1032     /// The requested present mode is not supported by the surface.
1033     UnsupportedPresentMode,
1034     /// The image configuration is not supported by the physical device.
1035     UnsupportedImageConfiguration,
1036 }
1037 
1038 impl error::Error for SwapchainCreationError {
1039     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>1040     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1041         match *self {
1042             SwapchainCreationError::OomError(ref err) => Some(err),
1043             _ => None,
1044         }
1045     }
1046 }
1047 
1048 impl fmt::Display for SwapchainCreationError {
1049     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>1050     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1051         write!(
1052             fmt,
1053             "{}",
1054             match *self {
1055                 SwapchainCreationError::OomError(_) => "not enough memory available",
1056                 SwapchainCreationError::DeviceLost => "the device was lost",
1057                 SwapchainCreationError::SurfaceLost => "the surface was lost",
1058                 SwapchainCreationError::SurfaceInUse => {
1059                     "the surface is already used by another swapchain"
1060                 }
1061                 SwapchainCreationError::NativeWindowInUse => {
1062                     "the window is already in use by another API"
1063                 }
1064                 SwapchainCreationError::MissingExtensionKHRSwapchain => {
1065                     "the `VK_KHR_swapchain` extension was not enabled"
1066                 }
1067                 SwapchainCreationError::MissingExtensionExtFullScreenExclusive => {
1068                     "the `VK_EXT_full_screen_exclusive` extension was not enabled"
1069                 }
1070                 SwapchainCreationError::OldSwapchainSurfaceMismatch => {
1071                     "surface mismatch between old and new swapchain"
1072                 }
1073                 SwapchainCreationError::OldSwapchainAlreadyUsed => {
1074                     "old swapchain has already been used to recreate a new one"
1075                 }
1076                 SwapchainCreationError::UnsupportedMinImagesCount => {
1077                     "the requested number of swapchain images is not supported by the surface"
1078                 }
1079                 SwapchainCreationError::UnsupportedMaxImagesCount => {
1080                     "the requested number of swapchain images is not supported by the surface"
1081                 }
1082                 SwapchainCreationError::UnsupportedFormat => {
1083                     "the requested image format is not supported by the surface"
1084                 }
1085                 SwapchainCreationError::UnsupportedDimensions => {
1086                     "the requested dimensions are not supported by the surface"
1087                 }
1088                 SwapchainCreationError::UnsupportedArrayLayers => {
1089                     "the requested array layers count is not supported by the surface"
1090                 }
1091                 SwapchainCreationError::UnsupportedUsageFlags => {
1092                     "the requested image usage is not supported by the surface"
1093                 }
1094                 SwapchainCreationError::UnsupportedSurfaceTransform => {
1095                     "the requested surface transform is not supported by the surface"
1096                 }
1097                 SwapchainCreationError::UnsupportedCompositeAlpha => {
1098                     "the requested composite alpha is not supported by the surface"
1099                 }
1100                 SwapchainCreationError::UnsupportedPresentMode => {
1101                     "the requested present mode is not supported by the surface"
1102                 }
1103                 SwapchainCreationError::UnsupportedImageConfiguration => {
1104                     "the requested image configuration is not supported by the physical device"
1105                 }
1106             }
1107         )
1108     }
1109 }
1110 
1111 impl From<Error> for SwapchainCreationError {
1112     #[inline]
from(err: Error) -> SwapchainCreationError1113     fn from(err: Error) -> SwapchainCreationError {
1114         match err {
1115             err @ Error::OutOfHostMemory => SwapchainCreationError::OomError(OomError::from(err)),
1116             err @ Error::OutOfDeviceMemory => SwapchainCreationError::OomError(OomError::from(err)),
1117             Error::DeviceLost => SwapchainCreationError::DeviceLost,
1118             Error::SurfaceLost => SwapchainCreationError::SurfaceLost,
1119             Error::NativeWindowInUse => SwapchainCreationError::NativeWindowInUse,
1120             _ => panic!("unexpected error: {:?}", err),
1121         }
1122     }
1123 }
1124 
1125 impl From<OomError> for SwapchainCreationError {
1126     #[inline]
from(err: OomError) -> SwapchainCreationError1127     fn from(err: OomError) -> SwapchainCreationError {
1128         SwapchainCreationError::OomError(err)
1129     }
1130 }
1131 
1132 impl From<CapabilitiesError> for SwapchainCreationError {
1133     #[inline]
from(err: CapabilitiesError) -> SwapchainCreationError1134     fn from(err: CapabilitiesError) -> SwapchainCreationError {
1135         match err {
1136             CapabilitiesError::OomError(err) => SwapchainCreationError::OomError(err),
1137             CapabilitiesError::SurfaceLost => SwapchainCreationError::SurfaceLost,
1138         }
1139     }
1140 }
1141 
1142 /// Represents the moment when the GPU will have access to a swapchain image.
1143 #[must_use]
1144 pub struct SwapchainAcquireFuture<W> {
1145     swapchain: Arc<Swapchain<W>>,
1146     image_id: usize,
1147     // Semaphore that is signalled when the acquire is complete. Empty if the acquire has already
1148     // happened.
1149     semaphore: Option<Semaphore>,
1150     // Fence that is signalled when the acquire is complete. Empty if the acquire has already
1151     // happened.
1152     fence: Option<Fence>,
1153     finished: AtomicBool,
1154 }
1155 
1156 impl<W> SwapchainAcquireFuture<W> {
1157     /// Returns the index of the image in the list of images returned when creating the swapchain.
1158     #[inline]
image_id(&self) -> usize1159     pub fn image_id(&self) -> usize {
1160         self.image_id
1161     }
1162 
1163     /// Returns the corresponding swapchain.
1164     #[inline]
swapchain(&self) -> &Arc<Swapchain<W>>1165     pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
1166         &self.swapchain
1167     }
1168 }
1169 
1170 unsafe impl<W> GpuFuture for SwapchainAcquireFuture<W> {
1171     #[inline]
cleanup_finished(&mut self)1172     fn cleanup_finished(&mut self) {}
1173 
1174     #[inline]
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>1175     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
1176         if let Some(ref semaphore) = self.semaphore {
1177             let mut sem = SubmitSemaphoresWaitBuilder::new();
1178             sem.add_wait_semaphore(&semaphore);
1179             Ok(SubmitAnyBuilder::SemaphoresWait(sem))
1180         } else {
1181             Ok(SubmitAnyBuilder::Empty)
1182         }
1183     }
1184 
1185     #[inline]
flush(&self) -> Result<(), FlushError>1186     fn flush(&self) -> Result<(), FlushError> {
1187         Ok(())
1188     }
1189 
1190     #[inline]
signal_finished(&self)1191     unsafe fn signal_finished(&self) {
1192         self.finished.store(true, Ordering::SeqCst);
1193     }
1194 
1195     #[inline]
queue_change_allowed(&self) -> bool1196     fn queue_change_allowed(&self) -> bool {
1197         true
1198     }
1199 
1200     #[inline]
queue(&self) -> Option<Arc<Queue>>1201     fn queue(&self) -> Option<Arc<Queue>> {
1202         None
1203     }
1204 
1205     #[inline]
check_buffer_access( &self, _: &dyn BufferAccess, _: bool, _: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>1206     fn check_buffer_access(
1207         &self,
1208         _: &dyn BufferAccess,
1209         _: bool,
1210         _: &Queue,
1211     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
1212         Err(AccessCheckError::Unknown)
1213     }
1214 
1215     #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, _: bool, _: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>1216     fn check_image_access(
1217         &self,
1218         image: &dyn ImageAccess,
1219         layout: ImageLayout,
1220         _: bool,
1221         _: &Queue,
1222     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
1223         let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
1224         if swapchain_image.image.internal_object() != image.inner().image.internal_object() {
1225             return Err(AccessCheckError::Unknown);
1226         }
1227 
1228         if self.swapchain.images[self.image_id]
1229             .undefined_layout
1230             .load(Ordering::Relaxed)
1231             && layout != ImageLayout::Undefined
1232         {
1233             return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
1234                 requested: layout,
1235             }));
1236         }
1237 
1238         if layout != ImageLayout::Undefined && layout != ImageLayout::PresentSrc {
1239             return Err(AccessCheckError::Denied(
1240                 AccessError::UnexpectedImageLayout {
1241                     allowed: ImageLayout::PresentSrc,
1242                     requested: layout,
1243                 },
1244             ));
1245         }
1246 
1247         Ok(None)
1248     }
1249 }
1250 
1251 unsafe impl<W> DeviceOwned for SwapchainAcquireFuture<W> {
1252     #[inline]
device(&self) -> &Arc<Device>1253     fn device(&self) -> &Arc<Device> {
1254         &self.swapchain.device
1255     }
1256 }
1257 
1258 impl<W> Drop for SwapchainAcquireFuture<W> {
drop(&mut self)1259     fn drop(&mut self) {
1260         if let Some(ref fence) = self.fence {
1261             fence.wait(None).unwrap(); // TODO: handle error?
1262             self.semaphore = None;
1263         }
1264 
1265         // TODO: if this future is destroyed without being presented, then eventually acquiring
1266         // a new image will block forever ; difficulty: hard
1267     }
1268 }
1269 
1270 /// Error that can happen when calling `Swapchain::acquire_fullscreen_exclusive` or `Swapchain::release_fullscreen_exclusive`
1271 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1272 #[repr(u32)]
1273 pub enum FullscreenExclusiveError {
1274     /// Not enough memory.
1275     OomError(OomError),
1276 
1277     /// Operation could not be completed for driver specific reasons.
1278     InitializationFailed,
1279 
1280     /// The surface is no longer accessible and must be recreated.
1281     SurfaceLost,
1282 
1283     /// Fullscreen exclusivity is already acquired.
1284     DoubleAcquire,
1285 
1286     /// Fullscreen exclusivity is not current acquired.
1287     DoubleRelease,
1288 
1289     /// Swapchain is not in fullscreen exclusive app controlled mode
1290     NotAppControlled,
1291 }
1292 
1293 impl From<Error> for FullscreenExclusiveError {
1294     #[inline]
from(err: Error) -> FullscreenExclusiveError1295     fn from(err: Error) -> FullscreenExclusiveError {
1296         match err {
1297             err @ Error::OutOfHostMemory => FullscreenExclusiveError::OomError(OomError::from(err)),
1298             err @ Error::OutOfDeviceMemory => {
1299                 FullscreenExclusiveError::OomError(OomError::from(err))
1300             }
1301             Error::SurfaceLost => FullscreenExclusiveError::SurfaceLost,
1302             Error::InitializationFailed => FullscreenExclusiveError::InitializationFailed,
1303             _ => panic!("unexpected error: {:?}", err),
1304         }
1305     }
1306 }
1307 
1308 impl From<OomError> for FullscreenExclusiveError {
1309     #[inline]
from(err: OomError) -> FullscreenExclusiveError1310     fn from(err: OomError) -> FullscreenExclusiveError {
1311         FullscreenExclusiveError::OomError(err)
1312     }
1313 }
1314 
1315 impl error::Error for FullscreenExclusiveError {
1316     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>1317     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1318         match *self {
1319             FullscreenExclusiveError::OomError(ref err) => Some(err),
1320             _ => None,
1321         }
1322     }
1323 }
1324 
1325 impl fmt::Display for FullscreenExclusiveError {
1326     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>1327     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1328         write!(
1329             fmt,
1330             "{}",
1331             match *self {
1332                 FullscreenExclusiveError::OomError(_) => "not enough memory",
1333                 FullscreenExclusiveError::SurfaceLost => {
1334                     "the surface of this swapchain is no longer valid"
1335                 }
1336                 FullscreenExclusiveError::InitializationFailed => {
1337                     "operation could not be completed for driver specific reasons"
1338                 }
1339                 FullscreenExclusiveError::DoubleAcquire =>
1340                     "fullscreen exclusivity is already acquired",
1341                 FullscreenExclusiveError::DoubleRelease => "fullscreen exclusivity is not acquired",
1342                 FullscreenExclusiveError::NotAppControlled => {
1343                     "swapchain is not in fullscreen exclusive app controlled mode"
1344                 }
1345             }
1346         )
1347     }
1348 }
1349 
1350 /// Error that can happen when calling `acquire_next_image`.
1351 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1352 #[repr(u32)]
1353 pub enum AcquireError {
1354     /// Not enough memory.
1355     OomError(OomError),
1356 
1357     /// The connection to the device has been lost.
1358     DeviceLost,
1359 
1360     /// The timeout of the function has been reached before an image was available.
1361     Timeout,
1362 
1363     /// The surface is no longer accessible and must be recreated.
1364     SurfaceLost,
1365 
1366     /// The swapchain has lost or doesn't have fullscreen exclusivity possibly for
1367     /// implementation-specific reasons outside of the application’s control.
1368     FullscreenExclusiveLost,
1369 
1370     /// The surface has changed in a way that makes the swapchain unusable. You must query the
1371     /// surface's new properties and recreate a new swapchain if you want to continue drawing.
1372     OutOfDate,
1373 
1374     /// Error during semaphore creation
1375     SemaphoreError(SemaphoreError),
1376 }
1377 
1378 impl error::Error for AcquireError {
1379     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>1380     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1381         match *self {
1382             AcquireError::OomError(ref err) => Some(err),
1383             _ => None,
1384         }
1385     }
1386 }
1387 
1388 impl fmt::Display for AcquireError {
1389     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>1390     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1391         write!(
1392             fmt,
1393             "{}",
1394             match *self {
1395                 AcquireError::OomError(_) => "not enough memory",
1396                 AcquireError::DeviceLost => "the connection to the device has been lost",
1397                 AcquireError::Timeout => "no image is available for acquiring yet",
1398                 AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
1399                 AcquireError::OutOfDate => "the swapchain needs to be recreated",
1400                 AcquireError::FullscreenExclusiveLost => {
1401                     "the swapchain no longer has fullscreen exclusivity"
1402                 }
1403                 AcquireError::SemaphoreError(_) => "error creating semaphore",
1404             }
1405         )
1406     }
1407 }
1408 
1409 impl From<SemaphoreError> for AcquireError {
from(err: SemaphoreError) -> Self1410     fn from(err: SemaphoreError) -> Self {
1411         AcquireError::SemaphoreError(err)
1412     }
1413 }
1414 
1415 impl From<OomError> for AcquireError {
1416     #[inline]
from(err: OomError) -> AcquireError1417     fn from(err: OomError) -> AcquireError {
1418         AcquireError::OomError(err)
1419     }
1420 }
1421 
1422 impl From<Error> for AcquireError {
1423     #[inline]
from(err: Error) -> AcquireError1424     fn from(err: Error) -> AcquireError {
1425         match err {
1426             err @ Error::OutOfHostMemory => AcquireError::OomError(OomError::from(err)),
1427             err @ Error::OutOfDeviceMemory => AcquireError::OomError(OomError::from(err)),
1428             Error::DeviceLost => AcquireError::DeviceLost,
1429             Error::SurfaceLost => AcquireError::SurfaceLost,
1430             Error::OutOfDate => AcquireError::OutOfDate,
1431             Error::FullscreenExclusiveLost => AcquireError::FullscreenExclusiveLost,
1432             _ => panic!("unexpected error: {:?}", err),
1433         }
1434     }
1435 }
1436 
1437 /// Represents a swapchain image being presented on the screen.
1438 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
1439 pub struct PresentFuture<P, W>
1440 where
1441     P: GpuFuture,
1442 {
1443     previous: P,
1444     queue: Arc<Queue>,
1445     swapchain: Arc<Swapchain<W>>,
1446     image_id: usize,
1447     present_region: Option<PresentRegion>,
1448     // True if `flush()` has been called on the future, which means that the present command has
1449     // been submitted.
1450     flushed: AtomicBool,
1451     // True if `signal_finished()` has been called on the future, which means that the future has
1452     // been submitted and has already been processed by the GPU.
1453     finished: AtomicBool,
1454 }
1455 
1456 impl<P, W> PresentFuture<P, W>
1457 where
1458     P: GpuFuture,
1459 {
1460     /// Returns the index of the image in the list of images returned when creating the swapchain.
1461     #[inline]
image_id(&self) -> usize1462     pub fn image_id(&self) -> usize {
1463         self.image_id
1464     }
1465 
1466     /// Returns the corresponding swapchain.
1467     #[inline]
swapchain(&self) -> &Arc<Swapchain<W>>1468     pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
1469         &self.swapchain
1470     }
1471 }
1472 
1473 unsafe impl<P, W> GpuFuture for PresentFuture<P, W>
1474 where
1475     P: GpuFuture,
1476 {
1477     #[inline]
cleanup_finished(&mut self)1478     fn cleanup_finished(&mut self) {
1479         self.previous.cleanup_finished();
1480     }
1481 
1482     #[inline]
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>1483     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
1484         if self.flushed.load(Ordering::SeqCst) {
1485             return Ok(SubmitAnyBuilder::Empty);
1486         }
1487 
1488         let queue = self.previous.queue().map(|q| q.clone());
1489 
1490         // TODO: if the swapchain image layout is not PRESENT, should add a transition command
1491         // buffer
1492 
1493         Ok(match self.previous.build_submission()? {
1494             SubmitAnyBuilder::Empty => {
1495                 let mut builder = SubmitPresentBuilder::new();
1496                 builder.add_swapchain(
1497                     &self.swapchain,
1498                     self.image_id as u32,
1499                     self.present_region.as_ref(),
1500                 );
1501                 SubmitAnyBuilder::QueuePresent(builder)
1502             }
1503             SubmitAnyBuilder::SemaphoresWait(sem) => {
1504                 let mut builder: SubmitPresentBuilder = sem.into();
1505                 builder.add_swapchain(
1506                     &self.swapchain,
1507                     self.image_id as u32,
1508                     self.present_region.as_ref(),
1509                 );
1510                 SubmitAnyBuilder::QueuePresent(builder)
1511             }
1512             SubmitAnyBuilder::CommandBuffer(cb) => {
1513                 // submit the command buffer by flushing previous.
1514                 // Since the implementation should remember being flushed it's safe to call build_submission multiple times
1515                 self.previous.flush()?;
1516 
1517                 let mut builder = SubmitPresentBuilder::new();
1518                 builder.add_swapchain(
1519                     &self.swapchain,
1520                     self.image_id as u32,
1521                     self.present_region.as_ref(),
1522                 );
1523                 SubmitAnyBuilder::QueuePresent(builder)
1524             }
1525             SubmitAnyBuilder::BindSparse(cb) => {
1526                 // submit the command buffer by flushing previous.
1527                 // Since the implementation should remember being flushed it's safe to call build_submission multiple times
1528                 self.previous.flush()?;
1529 
1530                 let mut builder = SubmitPresentBuilder::new();
1531                 builder.add_swapchain(
1532                     &self.swapchain,
1533                     self.image_id as u32,
1534                     self.present_region.as_ref(),
1535                 );
1536                 SubmitAnyBuilder::QueuePresent(builder)
1537             }
1538             SubmitAnyBuilder::QueuePresent(present) => {
1539                 unimplemented!() // TODO:
1540                                  /*present.submit();
1541                                  let mut builder = SubmitPresentBuilder::new();
1542                                  builder.add_swapchain(self.command_buffer.inner(), self.image_id);
1543                                  SubmitAnyBuilder::CommandBuffer(builder)*/
1544             }
1545         })
1546     }
1547 
1548     #[inline]
flush(&self) -> Result<(), FlushError>1549     fn flush(&self) -> Result<(), FlushError> {
1550         unsafe {
1551             // If `flushed` already contains `true`, then `build_submission` will return `Empty`.
1552 
1553             let build_submission_result = self.build_submission();
1554 
1555             if let &Err(FlushError::FullscreenExclusiveLost) = &build_submission_result {
1556                 self.swapchain
1557                     .fullscreen_exclusive_held
1558                     .store(false, Ordering::SeqCst);
1559             }
1560 
1561             match build_submission_result? {
1562                 SubmitAnyBuilder::Empty => {}
1563                 SubmitAnyBuilder::QueuePresent(present) => {
1564                     let present_result = present.submit(&self.queue);
1565 
1566                     if let &Err(SubmitPresentError::FullscreenExclusiveLost) = &present_result {
1567                         self.swapchain
1568                             .fullscreen_exclusive_held
1569                             .store(false, Ordering::SeqCst);
1570                     }
1571 
1572                     present_result?;
1573                 }
1574                 _ => unreachable!(),
1575             }
1576 
1577             self.flushed.store(true, Ordering::SeqCst);
1578             Ok(())
1579         }
1580     }
1581 
1582     #[inline]
signal_finished(&self)1583     unsafe fn signal_finished(&self) {
1584         self.flushed.store(true, Ordering::SeqCst);
1585         self.finished.store(true, Ordering::SeqCst);
1586         self.previous.signal_finished();
1587     }
1588 
1589     #[inline]
queue_change_allowed(&self) -> bool1590     fn queue_change_allowed(&self) -> bool {
1591         false
1592     }
1593 
1594     #[inline]
queue(&self) -> Option<Arc<Queue>>1595     fn queue(&self) -> Option<Arc<Queue>> {
1596         debug_assert!(match self.previous.queue() {
1597             None => true,
1598             Some(q) => q.is_same(&self.queue),
1599         });
1600 
1601         Some(self.queue.clone())
1602     }
1603 
1604     #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>1605     fn check_buffer_access(
1606         &self,
1607         buffer: &dyn BufferAccess,
1608         exclusive: bool,
1609         queue: &Queue,
1610     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
1611         self.previous.check_buffer_access(buffer, exclusive, queue)
1612     }
1613 
1614     #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>1615     fn check_image_access(
1616         &self,
1617         image: &dyn ImageAccess,
1618         layout: ImageLayout,
1619         exclusive: bool,
1620         queue: &Queue,
1621     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
1622         let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
1623         if swapchain_image.image.internal_object() == image.inner().image.internal_object() {
1624             // This future presents the swapchain image, which "unlocks" it. Therefore any attempt
1625             // to use this swapchain image afterwards shouldn't get granted automatic access.
1626             // Instead any attempt to access the image afterwards should get an authorization from
1627             // a later swapchain acquire future. Hence why we return `Unknown` here.
1628             Err(AccessCheckError::Unknown)
1629         } else {
1630             self.previous
1631                 .check_image_access(image, layout, exclusive, queue)
1632         }
1633     }
1634 }
1635 
1636 unsafe impl<P, W> DeviceOwned for PresentFuture<P, W>
1637 where
1638     P: GpuFuture,
1639 {
1640     #[inline]
device(&self) -> &Arc<Device>1641     fn device(&self) -> &Arc<Device> {
1642         self.queue.device()
1643     }
1644 }
1645 
1646 impl<P, W> Drop for PresentFuture<P, W>
1647 where
1648     P: GpuFuture,
1649 {
drop(&mut self)1650     fn drop(&mut self) {
1651         unsafe {
1652             if !*self.finished.get_mut() {
1653                 match self.flush() {
1654                     Ok(()) => {
1655                         // Block until the queue finished.
1656                         self.queue().unwrap().wait().unwrap();
1657                         self.previous.signal_finished();
1658                     }
1659                     Err(_) => {
1660                         // In case of error we simply do nothing, as there's nothing to do
1661                         // anyway.
1662                     }
1663                 }
1664             }
1665         }
1666     }
1667 }
1668 
1669 pub struct AcquiredImage {
1670     pub id: usize,
1671     pub suboptimal: bool,
1672 }
1673 
1674 /// Unsafe variant of `acquire_next_image`.
1675 ///
1676 /// # Safety
1677 ///
1678 /// - The semaphore and/or the fence must be kept alive until it is signaled.
1679 /// - The swapchain must not have been replaced by being passed as the old swapchain when creating
1680 ///   a new one.
acquire_next_image_raw<W>( swapchain: &Swapchain<W>, timeout: Option<Duration>, semaphore: Option<&Semaphore>, fence: Option<&Fence>, ) -> Result<AcquiredImage, AcquireError>1681 pub unsafe fn acquire_next_image_raw<W>(
1682     swapchain: &Swapchain<W>,
1683     timeout: Option<Duration>,
1684     semaphore: Option<&Semaphore>,
1685     fence: Option<&Fence>,
1686 ) -> Result<AcquiredImage, AcquireError> {
1687     let fns = swapchain.device.fns();
1688 
1689     let timeout_ns = if let Some(timeout) = timeout {
1690         timeout
1691             .as_secs()
1692             .saturating_mul(1_000_000_000)
1693             .saturating_add(timeout.subsec_nanos() as u64)
1694     } else {
1695         u64::MAX
1696     };
1697 
1698     let mut out = MaybeUninit::uninit();
1699     let r = check_errors(
1700         fns.khr_swapchain.acquire_next_image_khr(
1701             swapchain.device.internal_object(),
1702             swapchain.swapchain,
1703             timeout_ns,
1704             semaphore
1705                 .map(|s| s.internal_object())
1706                 .unwrap_or(ash::vk::Semaphore::null()),
1707             fence
1708                 .map(|f| f.internal_object())
1709                 .unwrap_or(ash::vk::Fence::null()),
1710             out.as_mut_ptr(),
1711         ),
1712     )?;
1713 
1714     let out = out.assume_init();
1715     let (id, suboptimal) = match r {
1716         Success::Success => (out as usize, false),
1717         Success::Suboptimal => (out as usize, true),
1718         Success::NotReady => return Err(AcquireError::Timeout),
1719         Success::Timeout => return Err(AcquireError::Timeout),
1720         s => panic!("unexpected success value: {:?}", s),
1721     };
1722 
1723     Ok(AcquiredImage { id, suboptimal })
1724 }
1725