1use crate::{
2 default_component_mapping, default_subresource_range, extent_2d_from_width_height, Device,
3 DeviceOwned, Fence, ImageAccess, ImageDimensions, ImageViewProperties, Queue, Semaphore,
4 Surface, ALLOCATION_CALLBACK_NONE,
5};
6use ash::{
7 extensions::khr,
8 prelude::VkResult,
9 vk::{self, Handle},
10};
11use std::{
12 cmp::{max, min},
13 error, fmt,
14 sync::Arc,
15};
16
17pub struct Swapchain {
20 handle: vk::SwapchainKHR,
21 swapchain_loader: khr::Swapchain,
22 properties: SwapchainProperties,
23 swapchain_images: Vec<Arc<SwapchainImage>>,
24
25 device: Arc<Device>,
27 surface: Arc<Surface>,
28}
29
30impl Swapchain {
31 pub fn new(
32 device: Arc<Device>,
33 surface: Arc<Surface>,
34 properties: SwapchainProperties,
35 ) -> Result<Self, SwapchainError> {
36 let swapchain_loader = khr::Swapchain::new(device.instance().inner(), device.inner());
37
38 let swapchain_create_info_builder =
39 properties.create_info_builder(surface.handle(), vk::SwapchainKHR::null());
40 let handle = unsafe {
41 swapchain_loader
42 .create_swapchain(&swapchain_create_info_builder, ALLOCATION_CALLBACK_NONE)
43 }
44 .map_err(|e| SwapchainError::Creation(e))?;
45
46 let vk_swapchain_images = unsafe { swapchain_loader.get_swapchain_images(handle) }
47 .map_err(|e| SwapchainError::GetSwapchainImages(e))?;
48
49 let swapchain_images: Vec<Arc<SwapchainImage>> = vk_swapchain_images
50 .into_iter()
51 .map(|image_handle| unsafe {
52 Arc::new(SwapchainImage::from_image_handle(
53 device.clone(),
54 image_handle,
55 &properties,
56 ))
57 })
58 .collect();
59
60 Ok(Self {
61 handle,
62 swapchain_loader,
63 properties,
64 swapchain_images,
65
66 device,
67 surface,
68 })
69 }
70
71 pub fn aquire_next_image(
73 &self,
74 timeout: u64,
75 semaphore: Option<&Semaphore>,
76 fence: Option<&Fence>,
77 ) -> VkResult<(u32, bool)> {
78 let semaphore_handle = if let Some(semaphore) = semaphore {
79 semaphore.handle()
80 } else {
81 vk::Semaphore::null()
82 };
83 let fence_handle = if let Some(fence) = fence {
84 fence.handle()
85 } else {
86 vk::Fence::null()
87 };
88
89 unsafe {
90 self.swapchain_loader.acquire_next_image(
91 self.handle,
92 timeout,
93 semaphore_handle,
94 fence_handle,
95 )
96 }
97 }
98
99 pub fn recreate(&mut self, properties: SwapchainProperties) -> Result<(), SwapchainError> {
102 let (new_handle, swapchain_images) = Self::recreate_common(&self, &properties)?;
103
104 unsafe {
105 self.swapchain_loader
106 .destroy_swapchain(self.handle, ALLOCATION_CALLBACK_NONE)
107 };
108
109 self.handle = new_handle;
110 self.properties = properties;
111 self.swapchain_images = swapchain_images;
112
113 Ok(())
114 }
115
116 pub fn recreate_replace(
123 self: &Arc<Self>,
124 properties: SwapchainProperties,
125 ) -> Result<Arc<Self>, SwapchainError> {
126 let (new_handle, swapchain_images) = Self::recreate_common(&self, &properties)?;
127
128 Ok(Arc::new(Self {
129 handle: new_handle,
130 swapchain_loader: self.swapchain_loader.clone(),
131 properties,
132 swapchain_images,
133 device: self.device.clone(),
134 surface: self.surface.clone(),
135 }))
136 }
137
138 fn recreate_common(
139 self: &Self,
140 properties: &SwapchainProperties,
141 ) -> Result<(vk::SwapchainKHR, Vec<Arc<SwapchainImage>>), SwapchainError> {
142 let swapchain_create_info_builder =
143 properties.create_info_builder(self.surface.handle(), self.handle);
144
145 let new_handle = unsafe {
146 self.swapchain_loader
147 .create_swapchain(&swapchain_create_info_builder, ALLOCATION_CALLBACK_NONE)
148 }
149 .map_err(|e| SwapchainError::Creation(e))?;
150
151 let vk_swapchain_images = unsafe { self.swapchain_loader.get_swapchain_images(new_handle) }
152 .map_err(|e| SwapchainError::GetSwapchainImages(e))?;
153
154 let swapchain_images: Vec<Arc<SwapchainImage>> = vk_swapchain_images
155 .into_iter()
156 .map(|image_handle| unsafe {
157 Arc::new(SwapchainImage::from_image_handle(
158 self.device.clone(),
159 image_handle,
160 &properties,
161 ))
162 })
163 .collect();
164
165 Ok((new_handle, swapchain_images))
166 }
167
168 pub fn image_view_properties(&self) -> ImageViewProperties {
169 let format = self.properties().surface_format.format;
170 let component_mapping = default_component_mapping();
171
172 let layer_count = self.properties().array_layers;
173 let view_type = if layer_count > 1 {
174 vk::ImageViewType::TYPE_2D_ARRAY
175 } else {
176 vk::ImageViewType::TYPE_2D
177 };
178 let subresource_range = vk::ImageSubresourceRange {
179 layer_count,
180 ..default_subresource_range(vk::ImageAspectFlags::COLOR)
181 };
182
183 ImageViewProperties {
184 format,
185 view_type,
186 component_mapping,
187 subresource_range,
188 ..ImageViewProperties::default()
189 }
190 }
191
192 pub fn queue_present(
193 &self,
194 queue: &Queue,
195 present_info: &vk::PresentInfoKHRBuilder,
196 ) -> VkResult<bool> {
197 unsafe {
198 self.swapchain_loader
199 .queue_present(queue.handle(), present_info)
200 }
201 }
202
203 #[inline]
206 pub fn handle(&self) -> vk::SwapchainKHR {
207 self.handle
208 }
209
210 #[inline]
211 pub fn swapchain_loader(&self) -> &khr::Swapchain {
212 &self.swapchain_loader
213 }
214
215 #[inline]
216 pub fn properties(&self) -> &SwapchainProperties {
217 &self.properties
218 }
219
220 #[inline]
221 pub fn surface(&self) -> &Arc<Surface> {
222 &self.surface
223 }
224
225 #[inline]
226 pub fn swapchain_images(&self) -> &Vec<Arc<SwapchainImage>> {
227 &self.swapchain_images
228 }
229}
230
231impl DeviceOwned for Swapchain {
232 #[inline]
233 fn device(&self) -> &Arc<Device> {
234 &self.device
235 }
236
237 #[inline]
238 fn handle_raw(&self) -> u64 {
239 self.handle.as_raw()
240 }
241}
242
243impl Drop for Swapchain {
244 fn drop(&mut self) {
245 unsafe {
246 self.swapchain_loader
247 .destroy_swapchain(self.handle, ALLOCATION_CALLBACK_NONE)
248 };
249 }
250}
251
252#[derive(Debug, Clone)]
261pub struct SwapchainProperties {
262 pub flags: vk::SwapchainCreateFlagsKHR,
263 pub image_count: u32,
264 pub pre_transform: vk::SurfaceTransformFlagsKHR,
265 pub composite_alpha: vk::CompositeAlphaFlagsKHR,
266 pub present_mode: vk::PresentModeKHR,
267 pub clipping_enabled: bool,
268
269 pub surface_format: vk::SurfaceFormatKHR,
271 pub width_height: [u32; 2],
272 pub array_layers: u32,
273 pub image_usage: vk::ImageUsageFlags,
274 pub sharing_mode: vk::SharingMode,
275 pub queue_family_indices: Vec<u32>,
276}
277
278impl Default for SwapchainProperties {
279 fn default() -> Self {
280 Self {
281 image_count: 1,
282 array_layers: 1,
283 sharing_mode: vk::SharingMode::EXCLUSIVE,
284 queue_family_indices: Vec::new(),
285 clipping_enabled: true,
286 present_mode: vk::PresentModeKHR::MAILBOX,
287 flags: vk::SwapchainCreateFlagsKHR::empty(),
288
289 surface_format: vk::SurfaceFormatKHR::default(),
291 width_height: [1, 1],
292 image_usage: vk::ImageUsageFlags::empty(),
293 pre_transform: vk::SurfaceTransformFlagsKHR::default(),
294 composite_alpha: vk::CompositeAlphaFlagsKHR::empty(),
295 }
296 }
297}
298
299impl SwapchainProperties {
300 pub fn new_default(
310 device: &Device,
311 surface: &Surface,
312 preferred_image_count: u32,
313 surface_format: vk::SurfaceFormatKHR,
314 composite_alpha: vk::CompositeAlphaFlagsKHR,
315 image_usage: vk::ImageUsageFlags,
316 window_dimensions: [u32; 2],
317 ) -> Result<Self, SwapchainError> {
318 let surface_capabilities = surface
319 .get_physical_device_surface_capabilities(device.physical_device())
320 .map_err(|e| SwapchainError::GetPhysicalDeviceSurfaceCapabilities(e))?;
321
322 let mut image_count = max(preferred_image_count, surface_capabilities.min_image_count);
323 if surface_capabilities.max_image_count != 0 {
325 image_count = min(image_count, surface_capabilities.max_image_count);
326 }
327
328 let extent = match surface_capabilities.current_extent.width {
329 std::u32::MAX => vk::Extent2D {
330 width: window_dimensions[0],
331 height: window_dimensions[1],
332 },
333 _ => surface_capabilities.current_extent,
334 };
335
336 let present_modes = surface
337 .get_physical_device_surface_present_modes(device.physical_device())
338 .map_err(|e| SwapchainError::GetPhysicalDeviceSurfacePresentModes(e))?;
339 let present_mode = present_modes
340 .into_iter()
341 .find(|&mode| mode == vk::PresentModeKHR::MAILBOX)
342 .unwrap_or(vk::PresentModeKHR::FIFO);
343
344 let pre_transform = if surface_capabilities
346 .supported_transforms
347 .contains(vk::SurfaceTransformFlagsKHR::IDENTITY)
348 {
349 vk::SurfaceTransformFlagsKHR::IDENTITY
350 } else {
351 surface_capabilities.current_transform
352 };
353
354 Ok(Self {
355 image_count,
356 surface_format,
357 width_height: [extent.width, extent.height],
358 image_usage,
359 sharing_mode: vk::SharingMode::EXCLUSIVE,
360 pre_transform,
361 composite_alpha,
362 present_mode,
363 clipping_enabled: true,
364 ..Self::default()
365 })
366 }
367
368 pub fn create_info_builder(
369 &self,
370 surface_handle: vk::SurfaceKHR,
371 old_swapchain_handle: vk::SwapchainKHR,
372 ) -> vk::SwapchainCreateInfoKHRBuilder {
373 vk::SwapchainCreateInfoKHR::builder()
374 .flags(self.flags)
375 .surface(surface_handle)
376 .min_image_count(self.image_count)
377 .image_format(self.surface_format.format)
378 .image_color_space(self.surface_format.color_space)
379 .image_extent(extent_2d_from_width_height(self.width_height))
380 .image_array_layers(self.array_layers)
381 .image_usage(self.image_usage)
382 .image_sharing_mode(self.sharing_mode)
383 .pre_transform(self.pre_transform)
384 .composite_alpha(self.composite_alpha)
385 .present_mode(self.present_mode)
386 .clipped(self.clipping_enabled)
387 .old_swapchain(old_swapchain_handle)
388 .queue_family_indices(&self.queue_family_indices)
389 }
390
391 pub fn dimensions(&self) -> ImageDimensions {
392 ImageDimensions::Dim2d {
393 width: self.width_height[0],
394 height: self.width_height[1],
395 array_layers: 1,
396 }
397 }
398}
399
400pub struct SwapchainImage {
403 handle: vk::Image,
404 dimensions: ImageDimensions,
405
406 device: Arc<Device>,
408}
409
410impl SwapchainImage {
411 pub(crate) unsafe fn from_image_handle(
413 device: Arc<Device>,
414 handle: vk::Image,
415 swapchain_properties: &SwapchainProperties,
416 ) -> Self {
417 Self {
418 handle,
419 dimensions: swapchain_properties.dimensions(),
420 device,
421 }
422 }
423
424 #[inline]
427 pub fn dimensions(&self) -> ImageDimensions {
428 self.dimensions
429 }
430}
431
432impl ImageAccess for SwapchainImage {
433 #[inline]
434 fn handle(&self) -> vk::Image {
435 self.handle
436 }
437
438 #[inline]
439 fn dimensions(&self) -> ImageDimensions {
440 self.dimensions
441 }
442}
443
444impl DeviceOwned for SwapchainImage {
445 #[inline]
446 fn device(&self) -> &Arc<Device> {
447 &self.device
448 }
449
450 #[inline]
451 fn handle_raw(&self) -> u64 {
452 self.handle.as_raw()
453 }
454}
455
456pub fn choose_composite_alpha(
464 surface_capabilities: vk::SurfaceCapabilitiesKHR,
465) -> vk::CompositeAlphaFlagsKHR {
466 let supported_composite_alpha = surface_capabilities.supported_composite_alpha;
467 let composite_alpha_preference_order = [
468 vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED,
469 vk::CompositeAlphaFlagsKHR::OPAQUE,
470 vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED,
471 vk::CompositeAlphaFlagsKHR::INHERIT,
472 ];
473 composite_alpha_preference_order
474 .into_iter()
475 .find(|&ca| supported_composite_alpha.contains(ca))
476 .expect("driver should support at least one type of composite alpha!")
477}
478
479#[derive(Debug, Clone)]
480pub enum SwapchainError {
481 GetPhysicalDeviceSurfaceCapabilities(vk::Result),
482 GetPhysicalDeviceSurfacePresentModes(vk::Result),
483 Creation(vk::Result),
484 GetSwapchainImages(vk::Result),
485}
486
487impl fmt::Display for SwapchainError {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 match self {
490 Self::GetPhysicalDeviceSurfaceCapabilities(e) => write!(
491 f,
492 "call to vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: {}",
493 e
494 ),
495 Self::GetPhysicalDeviceSurfacePresentModes(e) => write!(
496 f,
497 "call to vkGetPhysicalDeviceSurfacePresentModesKHR failed: {}",
498 e
499 ),
500 Self::Creation(e) => write!(f, "failed to create swapchain: {}", e),
501
502 Self::GetSwapchainImages(e) => {
503 write!(f, "call to vkGetSwapchainImagesKHR failed: {}", e)
504 }
505 }
506 }
507}
508
509impl error::Error for SwapchainError {
510 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
511 match self {
512 Self::GetPhysicalDeviceSurfaceCapabilities(e) => Some(e),
513 Self::GetPhysicalDeviceSurfacePresentModes(e) => Some(e),
514 Self::Creation(e) => Some(e),
515 Self::GetSwapchainImages(e) => Some(e),
516 }
517 }
518}