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