1use crate::Device;
2use crate::Instance;
3use crate::device::QueueType;
4use crate::error::FormatError;
5use ash::vk::{AllocationCallbacks, Handle, SwapchainKHR};
6use ash::{khr, vk};
7use std::ops::Deref;
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::sync::{Arc, Mutex};
10
11#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
12enum Priority {
13 Main,
14 Fallback,
15}
16
17#[derive(Debug, Clone)]
18struct Format<'a> {
19 inner: vk::SurfaceFormat2KHR<'a>,
20 priority: Priority,
21}
22
23#[derive(Debug, Clone)]
24struct PresentMode {
25 inner: vk::PresentModeKHR,
26 priority: Priority,
27}
28
29pub struct SwapchainBuilder {
30 instance: Arc<Instance>,
31 device: Arc<Device>,
32 swapchain_device: Arc<khr::swapchain::Device>,
33 allocation_callbacks: Option<AllocationCallbacks<'static>>,
34 desired_formats: Vec<Format<'static>>,
35 create_flags: vk::SwapchainCreateFlagsKHR,
36 desired_width: u32,
37 desired_height: u32,
38 array_layer_count: u32,
39 min_image_count: u32,
40 required_min_image_count: u32,
41 image_usage_flags: vk::ImageUsageFlags,
42 composite_alpha_flags_khr: vk::CompositeAlphaFlagsKHR,
43 desired_present_modes: Vec<PresentMode>,
44 pre_transform: vk::SurfaceTransformFlagsKHR,
45 clipped: bool,
46 old_swapchain: AtomicU64,
47 graphics_queue_index: usize,
48 present_queue_index: usize,
49}
50
51struct SurfaceFormatDetails {
52 capabilities: vk::SurfaceCapabilitiesKHR,
53 formats: Vec<vk::SurfaceFormatKHR>,
54 present_modes: Vec<vk::PresentModeKHR>,
55}
56
57fn query_surface_support_details(
58 phys_device: vk::PhysicalDevice,
59 surface_instance: Option<&khr::surface::Instance>,
60 surface: Option<vk::SurfaceKHR>,
61) -> crate::Result<SurfaceFormatDetails> {
62 let Some((surface_instance, surface)) = surface_instance.zip(surface) else {
63 return Err(crate::SwapchainError::SurfaceHandleNotProvided.into());
64 };
65
66 let capabilities =
67 unsafe { surface_instance.get_physical_device_surface_capabilities(phys_device, surface) }?;
68 let formats =
69 unsafe { surface_instance.get_physical_device_surface_formats(phys_device, surface) }?;
70 let present_modes = unsafe {
71 surface_instance.get_physical_device_surface_present_modes(phys_device, surface)
72 }?;
73
74 Ok(SurfaceFormatDetails {
75 capabilities,
76 formats,
77 present_modes,
78 })
79}
80
81fn default_formats<'a>() -> Vec<Format<'a>> {
82 vec![
83 Format {
84 inner: vk::SurfaceFormat2KHR::default().surface_format(
85 vk::SurfaceFormatKHR::default()
86 .format(vk::Format::B8G8R8A8_SRGB)
87 .color_space(vk::ColorSpaceKHR::SRGB_NONLINEAR),
88 ),
89 priority: Priority::Main,
90 },
91 Format {
92 inner: vk::SurfaceFormat2KHR::default().surface_format(
93 vk::SurfaceFormatKHR::default()
94 .format(vk::Format::R8G8B8_SRGB)
95 .color_space(vk::ColorSpaceKHR::SRGB_NONLINEAR),
96 ),
97 priority: Priority::Fallback,
98 },
99 ]
100}
101
102fn default_present_modes() -> Vec<PresentMode> {
103 vec![
104 PresentMode {
105 inner: vk::PresentModeKHR::MAILBOX,
106 priority: Priority::Main,
107 },
108 PresentMode {
109 inner: vk::PresentModeKHR::FIFO,
110 priority: Priority::Fallback,
111 },
112 ]
113}
114
115fn find_desired_surface_format(
116 available: &[vk::SurfaceFormatKHR],
117 desired: &mut [Format],
118) -> crate::Result<vk::SurfaceFormatKHR> {
119 if !desired.is_sorted_by_key(|f| f.priority.clone()) {
120 desired.sort_unstable_by_key(|f| f.priority.clone());
121 }
122
123 for desired in desired.iter() {
124 for available in available {
125 if desired.inner.surface_format.format == available.format
126 && desired.inner.surface_format.color_space == available.color_space
127 {
128 return Ok(desired.inner.surface_format);
129 }
130 }
131 }
132
133 Err(crate::SwapchainError::NoSuitableDesiredFormat(FormatError {
134 available: available.to_vec(),
135 desired: desired.iter().map(|d| d.inner.surface_format).collect(),
136 })
137 .into())
138}
139
140fn find_best_surface_format(
141 available: &[vk::SurfaceFormatKHR],
142 desired: &mut [Format],
143) -> vk::SurfaceFormatKHR {
144 find_desired_surface_format(available, desired).unwrap_or(available[0])
145}
146
147fn find_present_mode(
148 available: &[vk::PresentModeKHR],
149 desired: &mut [PresentMode],
150) -> vk::PresentModeKHR {
151 if !desired.is_sorted_by_key(|f| f.priority.clone()) {
152 desired.sort_unstable_by_key(|f| f.priority.clone());
153 }
154
155 for desired in desired {
156 for available in available {
157 if &desired.inner == available {
158 return *available;
159 }
160 }
161 }
162
163 vk::PresentModeKHR::FIFO
164}
165
166impl SwapchainBuilder {
167 fn find_extent(&self, capabilities: &vk::SurfaceCapabilitiesKHR) -> vk::Extent2D {
168 if capabilities.current_extent.width != u32::MAX {
169 capabilities.current_extent
170 } else {
171 let mut actual_extent = vk::Extent2D::default()
172 .width(self.desired_width)
173 .height(self.desired_height);
174
175 actual_extent.width = capabilities
176 .min_image_extent
177 .width
178 .max(capabilities.max_image_extent.width.min(actual_extent.width));
179 actual_extent.height = capabilities.min_image_extent.height.max(
180 capabilities
181 .max_image_extent
182 .height
183 .min(actual_extent.height),
184 );
185
186 actual_extent
187 }
188 }
189
190 pub fn new(instance: Arc<Instance>, device: Arc<Device>) -> Self {
191 Self {
192 graphics_queue_index: device.get_queue(QueueType::Graphics).unwrap().0,
193 present_queue_index: device.get_queue(QueueType::Present).unwrap().0,
194 swapchain_device: Arc::new(khr::swapchain::Device::new(
195 &instance.instance,
196 device.as_ref().as_ref(),
197 )),
198 instance,
199 device,
200 allocation_callbacks: None,
201 desired_formats: Vec::with_capacity(4),
202 create_flags: vk::SwapchainCreateFlagsKHR::default(),
203 desired_width: 256,
204 desired_height: 256,
205 array_layer_count: 1,
206 min_image_count: 0,
207 required_min_image_count: 0,
208 image_usage_flags: vk::ImageUsageFlags::COLOR_ATTACHMENT,
209 pre_transform: vk::SurfaceTransformFlagsKHR::default(),
210 desired_present_modes: Vec::with_capacity(4),
211 composite_alpha_flags_khr: vk::CompositeAlphaFlagsKHR::OPAQUE,
212 clipped: true,
213 old_swapchain: Default::default(),
214 }
215 }
216
217 pub fn desired_format(mut self, format: vk::SurfaceFormat2KHR<'static>) -> Self {
218 self.desired_formats.push(Format {
219 inner: format,
220 priority: Priority::Main,
221 });
222 self
223 }
224
225 pub fn desired_size(mut self, size: vk::Extent2D) -> Self {
226 self.desired_width = size.width;
227 self.desired_height = size.height;
228 self
229 }
230
231 pub fn fallback_format(mut self, format: vk::SurfaceFormat2KHR<'static>) -> Self {
232 self.desired_formats.push(Format {
233 inner: format,
234 priority: Priority::Fallback,
235 });
236 self
237 }
238
239 pub fn use_default_format_selection(mut self) -> Self {
246 self.desired_formats = default_formats();
247 self
248 }
249
250 pub fn desired_present_mode(mut self, present_mode: vk::PresentModeKHR) -> Self {
251 self.desired_present_modes.push(PresentMode {
252 inner: present_mode,
253 priority: Priority::Main,
254 });
255 self
256 }
257
258 pub fn fallback_present_mode(mut self, present_mode: vk::PresentModeKHR) -> Self {
259 self.desired_present_modes.push(PresentMode {
260 inner: present_mode,
261 priority: Priority::Fallback,
262 });
263 self
264 }
265
266 pub fn use_default_present_modes(mut self) -> Self {
267 self.desired_present_modes = default_present_modes();
268 self
269 }
270
271 pub fn desired_min_image_count(mut self, min_image_count: u32) -> Self {
277 self.min_image_count = min_image_count;
278 self
279 }
280
281 pub fn clipped(mut self, clipped: bool) -> Self {
288 self.clipped = clipped;
289 self
290 }
291
292 pub fn create_flags(mut self, flags: vk::SwapchainCreateFlagsKHR) -> Self {
293 self.create_flags = flags;
294 self
295 }
296
297 pub fn image_usage_flags(mut self, flags: vk::ImageUsageFlags) -> Self {
300 self.image_usage_flags = flags;
301 self
302 }
303
304 pub fn add_image_usage_flags(mut self, flags: vk::ImageUsageFlags) -> Self {
306 self.image_usage_flags |= flags;
307 self
308 }
309
310 pub fn allocation_callbacks(
311 mut self,
312 allocation_callbacks: AllocationCallbacks<'static>,
313 ) -> Self {
314 self.allocation_callbacks = Some(allocation_callbacks);
315 self
316 }
317
318 pub fn set_old_swapchain(&self, swapchain: Swapchain) {
323 if swapchain.destroy_image_views().is_err() {
324 #[cfg(feature = "enable_tracing")]
325 tracing::warn!("Could not destroy swapchain image views");
326 return;
327 };
328 self.old_swapchain
329 .store(swapchain.swapchain.as_raw(), Ordering::Relaxed);
330 }
331
332 pub fn build(&self) -> crate::Result<Swapchain> {
333 if self.instance.surface.is_none() {
334 return Err(crate::SwapchainError::SurfaceHandleNotProvided.into());
335 };
336
337 let mut desired_formats = self.desired_formats.clone();
338 if desired_formats.is_empty() {
339 desired_formats = default_formats();
340 };
341
342 let mut desired_present_modes = self.desired_present_modes.clone();
343 if desired_present_modes.is_empty() {
344 desired_present_modes = default_present_modes();
345 }
346
347 let surface_support = query_surface_support_details(
348 *self.device.physical_device().as_ref(),
349 self.instance.surface_instance.as_ref(),
350 self.instance.surface,
351 )?;
352
353 let mut image_count = self.min_image_count;
354 if image_count >= 1 {
355 if self.required_min_image_count < surface_support.capabilities.min_image_count {
356 return Err(crate::SwapchainError::RequiredMinImageCountTooLow.into());
357 }
358
359 image_count = surface_support.capabilities.min_image_count;
360 } else if image_count == 0 {
361 image_count = surface_support.capabilities.min_image_count + 1;
364 } else if image_count < surface_support.capabilities.min_image_count {
365 image_count = surface_support.capabilities.min_image_count
366 }
367
368 if surface_support.capabilities.max_image_count > 0
369 && image_count > surface_support.capabilities.max_image_count
370 {
371 image_count = surface_support.capabilities.max_image_count;
372 }
373
374 let surface_format =
375 find_best_surface_format(&surface_support.formats, &mut desired_formats);
376
377 let extent = self.find_extent(&surface_support.capabilities);
378
379 let mut image_array_layers = self.array_layer_count;
380 if surface_support.capabilities.max_image_array_layers < image_array_layers {
381 image_array_layers = surface_support.capabilities.max_image_array_layers;
382 }
383 if image_array_layers == 0 {
384 image_array_layers = 1;
385 }
386
387 let present_mode =
388 find_present_mode(&surface_support.present_modes, &mut desired_present_modes);
389
390 let is_unextended_present_mode =
391 matches!(
392 present_mode,
393 |vk::PresentModeKHR::IMMEDIATE| vk::PresentModeKHR::MAILBOX
394 | vk::PresentModeKHR::FIFO
395 | vk::PresentModeKHR::FIFO_RELAXED
396 );
397
398 if is_unextended_present_mode
399 && !surface_support
400 .capabilities
401 .supported_usage_flags
402 .contains(self.image_usage_flags)
403 {
404 return Err(crate::SwapchainError::RequiredUsageNotSupported.into());
405 };
406
407 let mut pre_transform = self.pre_transform;
408 if pre_transform == vk::SurfaceTransformFlagsKHR::default() {
409 pre_transform = surface_support.capabilities.current_transform;
410 }
411
412 let old_swapchain = self.old_swapchain.load(Ordering::Relaxed);
413
414 let mut swapchain_create_info = vk::SwapchainCreateInfoKHR::default()
415 .flags(self.create_flags)
416 .surface(self.instance.surface.unwrap())
417 .min_image_count(image_count)
418 .image_format(surface_format.format)
419 .image_color_space(surface_format.color_space)
420 .image_extent(extent)
421 .image_array_layers(image_array_layers)
422 .image_usage(self.image_usage_flags)
423 .pre_transform(pre_transform)
424 .composite_alpha(self.composite_alpha_flags_khr)
425 .present_mode(present_mode)
426 .clipped(self.clipped)
427 .old_swapchain(SwapchainKHR::from_raw(old_swapchain));
428
429 let queue_family_indices = [
430 self.graphics_queue_index as _,
431 self.present_queue_index as _,
432 ];
433
434 if self.graphics_queue_index != self.present_queue_index {
435 swapchain_create_info.image_sharing_mode = vk::SharingMode::CONCURRENT;
436 swapchain_create_info =
437 swapchain_create_info.queue_family_indices(&queue_family_indices);
438 } else {
439 swapchain_create_info.image_sharing_mode = vk::SharingMode::EXCLUSIVE;
440 }
441
442 let swapchain = unsafe {
443 self.swapchain_device
444 .create_swapchain(&swapchain_create_info, self.allocation_callbacks.as_ref())
445 }
446 .map_err(|_| crate::SwapchainError::FailedCreateSwapchain)?;
447
448 if old_swapchain != 0 {
449 unsafe {
450 self.swapchain_device.destroy_swapchain(
451 SwapchainKHR::from_raw(old_swapchain),
452 self.allocation_callbacks.as_ref(),
453 )
454 }
455 }
456
457 Ok(Swapchain {
458 device: self.device.clone(),
459 swapchain,
460 extent,
461 swapchain_device: self.swapchain_device.clone(),
462 image_format: surface_format.format,
463 image_usage_flags: self.image_usage_flags,
464 instance_version: self.instance.instance_version,
465 allocation_callbacks: self.allocation_callbacks,
466 image_views: Mutex::new(Vec::with_capacity(image_count as _)),
467 })
468 }
469}
470
471pub struct Swapchain {
472 device: Arc<Device>,
473 swapchain: vk::SwapchainKHR,
474 swapchain_device: Arc<khr::swapchain::Device>,
475 pub image_format: vk::Format,
476 pub extent: vk::Extent2D,
477 image_usage_flags: vk::ImageUsageFlags,
478 instance_version: u32,
479 allocation_callbacks: Option<AllocationCallbacks<'static>>,
480 image_views: Mutex<Vec<vk::ImageView>>,
481}
482
483impl Swapchain {
484 pub fn get_images(&self) -> crate::Result<Vec<vk::Image>> {
485 let images = unsafe { self.swapchain_device.get_swapchain_images(self.swapchain) }?;
486
487 Ok(images)
488 }
489
490 pub fn destroy_image_views(&self) -> crate::Result<()> {
491 let mut image_views = self.image_views.lock().unwrap();
492
493 for image_view in image_views.drain(..) {
494 unsafe {
495 self.device
496 .device()
497 .destroy_image_view(image_view, self.allocation_callbacks.as_ref())
498 }
499 }
500
501 Ok(())
502 }
503
504 pub fn get_image_views(&self) -> crate::Result<Vec<vk::ImageView>> {
505 let images = self.get_images()?;
506
507 let mut desired_flags =
508 vk::ImageViewUsageCreateInfo::default().usage(self.image_usage_flags);
509
510 let views: Vec<_> = images
511 .into_iter()
512 .map(|image| {
513 let mut create_info = vk::ImageViewCreateInfo::default();
514
515 if self.instance_version >= vk::API_VERSION_1_1 {
516 create_info = create_info.push_next(&mut desired_flags);
517 }
518
519 create_info.image = image;
520 create_info.view_type = vk::ImageViewType::TYPE_2D;
521 create_info.format = self.image_format;
522 create_info.components.r = vk::ComponentSwizzle::IDENTITY;
523 create_info.components.g = vk::ComponentSwizzle::IDENTITY;
524 create_info.components.b = vk::ComponentSwizzle::IDENTITY;
525 create_info.components.a = vk::ComponentSwizzle::IDENTITY;
526 create_info.subresource_range.aspect_mask = vk::ImageAspectFlags::COLOR;
527 create_info.subresource_range.base_mip_level = 0;
528 create_info.subresource_range.level_count = 1;
529 create_info.subresource_range.base_array_layer = 0;
530 create_info.subresource_range.layer_count = 1;
531
532 unsafe {
533 self.device
534 .device()
535 .create_image_view(&create_info, self.allocation_callbacks.as_ref())
536 }
537 .map_err(Into::into)
538 })
539 .collect::<crate::Result<_>>()?;
540
541 {
542 let mut image_views = self.image_views.lock().unwrap();
543 *image_views = views.clone();
544 }
545
546 Ok(views)
547 }
548
549 pub fn destroy(&self) {
550 unsafe {
551 self.swapchain_device
552 .destroy_swapchain(self.swapchain, self.allocation_callbacks.as_ref())
553 };
554 }
555}
556
557impl AsRef<SwapchainKHR> for Swapchain {
558 fn as_ref(&self) -> &SwapchainKHR {
559 &self.swapchain
560 }
561}
562
563impl Deref for Swapchain {
564 type Target = khr::swapchain::Device;
565
566 fn deref(&self) -> &Self::Target {
567 &self.swapchain_device
568 }
569}