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