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