1use std::sync::Arc;
2
3use ash::{extensions::khr, vk};
4
5use crate::{Device, sync::*, image::*, Format, Error, Surface};
6
7#[derive(thiserror::Error, Debug)]
9pub enum SwapchainError {
10 #[error("No suitable depth format is available")]
12 NoSuitableDepthFormat,
13}
14
15pub struct Swapchain {
17 device: Arc<Device>,
18 #[allow(dead_code)]
19 surface: Surface,
20
21 swapchain_loader: khr::Swapchain,
22 swapchain: vk::SwapchainKHR,
23
24 extent: vk::Extent2D,
25
26 pub images: Vec<Image>,
27 pub surface_format: Format,
28 pub depth_format: Format,
29}
30
31impl Drop for Swapchain {
32 fn drop(&mut self) {
33 unsafe {
34 self.swapchain_loader
35 .destroy_swapchain(self.swapchain, None);
36 }
37 }
38}
39
40impl Swapchain {
41 pub fn new(
54 device: &Arc<Device>,
55 window: &winit::window::Window,
56 ) -> Result<Self, Error> {
57 let surface = Surface::new(&device.instance, &window)?;
58
59 let (
60 swapchain_loader,
61 swapchain,
62 extent,
63 images,
64 surface_format,
65 depth_format,
66 ) = Self::create_swapchain(device, &surface, window, None)?;
67
68 Ok(Self {
69 device: Arc::clone(&device),
70 surface,
71 swapchain_loader,
72 swapchain,
73 extent,
74 images,
75 surface_format,
76 depth_format,
77 })
78 }
79
80 pub fn recreate(&mut self, window: &winit::window::Window) -> Result<(), Error> {
96 self.device.wait_idle()?;
97
98 let (
99 swapchain_loader,
100 swapchain,
101 extent,
102 images,
103 surface_format,
104 depth_format,
105 ) = Self::create_swapchain(&self.device, &self.surface, window, Some(self.swapchain))?;
106
107 unsafe {
108 self.swapchain_loader
109 .destroy_swapchain(self.swapchain, None);
110 }
111
112 self.swapchain_loader = swapchain_loader;
113 self.swapchain = swapchain;
114 self.extent = extent;
115 self.images = images;
116 self.surface_format = surface_format;
117 self.depth_format = depth_format;
118
119 Ok(())
120 }
121
122 pub fn next_image(&self, semaphore: &Semaphore) -> Result<(u32, bool), Error> {
139 Ok(unsafe {
140 self.swapchain_loader.acquire_next_image(
141 self.swapchain,
142 u64::MAX,
143 **semaphore,
144 vk::Fence::null(),
145 )?
146 })
147 }
148
149 pub fn present(&self, image_index: u32, wait_semaphore: &Semaphore) -> Result<bool, Error> {
166 let swapchains = [self.swapchain];
167 let wait_semaphores = [**wait_semaphore];
168 let image_indices = [image_index];
169
170 let present_info = vk::PresentInfoKHR::builder()
171 .wait_semaphores(&wait_semaphores)
172 .swapchains(&swapchains)
173 .image_indices(&image_indices);
174
175 Ok(unsafe { self.swapchain_loader.queue_present(self.device.queue.queue, &present_info)? })
176 }
177
178 pub fn aspect_ratio(&self) -> f32 {
192 (self.extent.width as f32) / (self.extent.height as f32)
193 }
194
195 pub fn extent(&self) -> (u32, u32) {
208 (self.extent.width, self.extent.height)
209 }
210
211 fn create_swapchain(
212 device: &Arc<Device>,
213 surface: &Surface,
214 window: &winit::window::Window,
215 old_swapchain: Option<vk::SwapchainKHR>,
216 ) -> Result<(
217 khr::Swapchain,
218 vk::SwapchainKHR,
219 vk::Extent2D,
220 Vec<Image>,
221 Format,
222 Format,
223 ), Error> {
224 let surface_capabilities = unsafe {
225 surface
226 .surface_loader
227 .get_physical_device_surface_capabilities(
228 device.physical_device,
229 surface.surface,
230 )?
231 };
232 let surface_formats = unsafe {
233 surface
234 .surface_loader
235 .get_physical_device_surface_formats(
236 device.physical_device,
237 surface.surface,
238 )?
239 };
240 let present_modes = unsafe {
241 surface
242 .surface_loader
243 .get_physical_device_surface_present_modes(
244 device.physical_device,
245 surface.surface,
246 )?
247 };
248
249 let image_format = surface_formats
250 .iter()
251 .find(|format| {
252 format.format == vk::Format::R8G8B8A8_SRGB
253 && format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
254 })
255 .unwrap_or(&surface_formats[0]);
256
257 let present_mode = *present_modes
258 .iter()
259 .find(|mode| **mode == vk::PresentModeKHR::FIFO)
260 .unwrap_or(&present_modes[0]);
261
262 let window_extent = window.inner_size();
263 let extent = vk::Extent2D {
264 width: window_extent.width.clamp(
265 surface_capabilities.min_image_extent.width,
266 surface_capabilities.max_image_extent.width,
267 ),
268 height: window_extent.height.clamp(
269 surface_capabilities.min_image_extent.height,
270 surface_capabilities.max_image_extent.height,
271 ),
272 };
273
274 let queue_families = [device.queue.family];
275
276 let image_count = if surface_capabilities.max_image_count == 0 {
277 surface_capabilities.min_image_count + 1
278 } else {
279 (surface_capabilities.min_image_count + 1).min(surface_capabilities.max_image_count)
280 };
281
282 let mut swapchain_info = vk::SwapchainCreateInfoKHR::builder()
283 .surface(surface.surface)
284 .min_image_count(image_count)
285 .image_format(image_format.format)
286 .image_color_space(image_format.color_space)
287 .image_extent(extent)
288 .image_array_layers(1)
289 .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
290 .image_sharing_mode(vk::SharingMode::EXCLUSIVE)
291 .queue_family_indices(&queue_families)
292 .pre_transform(surface_capabilities.current_transform)
293 .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
294 .present_mode(present_mode)
295 .clipped(true);
296
297 match old_swapchain {
298 Some(swapchain) => swapchain_info = swapchain_info.old_swapchain(swapchain),
299 None => (),
300 };
301
302 let swapchain_loader = khr::Swapchain::new(&device.instance, &device);
303 let swapchain = unsafe { swapchain_loader.create_swapchain(&swapchain_info, None)? };
304
305 let images = unsafe { swapchain_loader.get_swapchain_images(swapchain)? }.into_iter()
306 .map(|i| Image::from_vk_image(device, i, None, extent.width, extent.height, image_format.format, ImageAspectFlags::COLOR))
307 .collect::<Result<Vec<_>, _>>()?;
308
309 let depth_format = [
310 vk::Format::D32_SFLOAT,
311 vk::Format::D32_SFLOAT_S8_UINT,
312 vk::Format::D24_UNORM_S8_UINT
313 ].into_iter()
314 .find(|format| {
315 let props = unsafe { device.instance.get_physical_device_format_properties(device.physical_device, *format) };
316 props.optimal_tiling_features.contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT)
317 })
318 .ok_or(SwapchainError::NoSuitableDepthFormat)?;
319
320 Ok((
321 swapchain_loader,
322 swapchain,
323 extent,
324 images,
325 image_format.format,
326 depth_format,
327 ))
328 }
329}