Skip to main content

rotex_vulkan/backend/vulkan/
swapchain.rs

1use ash::vk;
2
3use super::device::{Device, QueueCategory};
4use super::sync::Semaphore;
5use crate::core::Instance;
6use crate::error::{Error, ErrorKind, Severity, vk_error};
7
8pub struct Surface {
9    pub(crate) loader: ash::khr::surface::Instance,
10    pub(crate) surface: vk::SurfaceKHR,
11}
12
13impl Surface {
14    pub fn new(instance: &Instance, surface: vk::SurfaceKHR) -> Self {
15        let loader = ash::khr::surface::Instance::new(instance.entry(), instance.instance());
16        Self { loader, surface }
17    }
18
19    pub fn loader(&self) -> &ash::khr::surface::Instance {
20        &self.loader
21    }
22
23    pub fn handle(&self) -> vk::SurfaceKHR {
24        self.surface
25    }
26
27    pub fn destroy(&mut self) {
28        unsafe {
29            self.loader.destroy_surface(self.surface, None);
30        }
31    }
32}
33
34pub struct Swapchain {
35    pub(crate) loader: ash::khr::swapchain::Device,
36    pub(crate) swapchain: vk::SwapchainKHR,
37    pub(crate) _surface: vk::SurfaceKHR,
38    pub(crate) format: vk::Format,
39    pub(crate) color_space: vk::ColorSpaceKHR,
40    pub(crate) extent: vk::Extent2D,
41    pub(crate) images: Vec<vk::Image>,
42    pub(crate) image_views: Vec<vk::ImageView>,
43}
44
45fn clamp_extent(extent: vk::Extent2D, capabilities: &vk::SurfaceCapabilitiesKHR) -> vk::Extent2D {
46    vk::Extent2D {
47        width: extent.width.clamp(
48            capabilities.min_image_extent.width,
49            capabilities.max_image_extent.width,
50        ),
51        height: extent.height.clamp(
52            capabilities.min_image_extent.height,
53            capabilities.max_image_extent.height,
54        ),
55    }
56}
57
58impl Swapchain {
59    pub fn new(
60        instance: &Instance,
61        device: &Device,
62        surface: &Surface,
63        extent_hint: vk::Extent2D,
64    ) -> Result<Self, Error> {
65        Self::new_with_old(
66            instance,
67            device,
68            surface,
69            extent_hint,
70            vk::SwapchainKHR::null(),
71        )
72    }
73
74    pub fn new_with_old(
75        instance: &Instance,
76        device: &Device,
77        surface: &Surface,
78        extent_hint: vk::Extent2D,
79        old_swapchain: vk::SwapchainKHR,
80    ) -> Result<Self, Error> {
81        let queue = device
82            .queues()
83            .iter()
84            .find(|allocation| allocation.category == QueueCategory::Graphics)
85            .ok_or(Error {
86                kind: ErrorKind::NoCompatibleDevice,
87                severity: Severity::Fatal,
88            })?;
89
90        let surface_capabilities = unsafe {
91            surface.loader().get_physical_device_surface_capabilities(
92                device.physical_device(),
93                surface.handle(),
94            )
95        }
96        .map_err(vk_error)?;
97        let surface_formats = unsafe {
98            surface
99                .loader()
100                .get_physical_device_surface_formats(device.physical_device(), surface.handle())
101        }
102        .map_err(vk_error)?;
103        let present_modes = unsafe {
104            surface.loader().get_physical_device_surface_present_modes(
105                device.physical_device(),
106                surface.handle(),
107            )
108        }
109        .map_err(vk_error)?;
110
111        let preferred_format = [vk::Format::B8G8R8A8_SRGB, vk::Format::R8G8B8A8_SRGB];
112        let preferred_color_space = vk::ColorSpaceKHR::SRGB_NONLINEAR;
113        let surface_format = surface_formats
114            .iter()
115            .find(|format| {
116                preferred_format.contains(&format.format)
117                    && format.color_space == preferred_color_space
118            })
119            .or_else(|| surface_formats.first())
120            .ok_or(Error {
121                kind: ErrorKind::Vulkan(vk::Result::ERROR_FORMAT_NOT_SUPPORTED),
122                severity: Severity::Fatal,
123            })?;
124
125        let present_mode = if present_modes.contains(&vk::PresentModeKHR::MAILBOX) {
126            vk::PresentModeKHR::MAILBOX
127        } else {
128            vk::PresentModeKHR::FIFO
129        };
130
131        let extent = if surface_capabilities.current_extent.width != u32::MAX {
132            surface_capabilities.current_extent
133        } else {
134            clamp_extent(extent_hint, &surface_capabilities)
135        };
136
137        let mut image_count = surface_capabilities.min_image_count + 1;
138        if surface_capabilities.max_image_count > 0 {
139            image_count = image_count.min(surface_capabilities.max_image_count);
140        }
141
142        let queue_family_indices = [queue.family_index];
143        let swapchain_create_info = vk::SwapchainCreateInfoKHR::default()
144            .surface(surface.handle())
145            .min_image_count(image_count)
146            .image_format(surface_format.format)
147            .image_color_space(surface_format.color_space)
148            .image_extent(extent)
149            .image_array_layers(1)
150            .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
151            .image_sharing_mode(vk::SharingMode::EXCLUSIVE)
152            .queue_family_indices(&queue_family_indices)
153            .pre_transform(surface_capabilities.current_transform)
154            .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
155            .present_mode(present_mode)
156            .clipped(true)
157            .old_swapchain(old_swapchain);
158
159        let swapchain_loader = ash::khr::swapchain::Device::new(&instance.instance(), &device.logical_device());
160        let swapchain = unsafe { swapchain_loader.create_swapchain(&swapchain_create_info, None) }
161            .map_err(vk_error)?;
162        let images =
163            unsafe { swapchain_loader.get_swapchain_images(swapchain) }.map_err(vk_error)?;
164
165        let image_views = images
166            .iter()
167            .map(|image| {
168                let view_info = vk::ImageViewCreateInfo::default()
169                    .image(*image)
170                    .view_type(vk::ImageViewType::TYPE_2D)
171                    .format(surface_format.format)
172                    .subresource_range(
173                        vk::ImageSubresourceRange::default()
174                            .aspect_mask(vk::ImageAspectFlags::COLOR)
175                            .level_count(1)
176                            .layer_count(1),
177                    );
178                unsafe { device.logical_device().create_image_view(&view_info, None) }
179                    .map_err(vk_error)
180            })
181            .collect::<Result<Vec<_>, _>>()?;
182
183        Ok(Self {
184            loader: swapchain_loader,
185            swapchain,
186            _surface: surface.handle(),
187            format: surface_format.format,
188            color_space: surface_format.color_space,
189            extent,
190            images,
191            image_views,
192        })
193    }
194
195    pub fn acquire_next_image(&self, semaphore: &Semaphore) -> Result<(u32, bool), Error> {
196        unsafe {
197            self.loader.acquire_next_image(
198                self.swapchain,
199                u64::MAX,
200                semaphore.handle,
201                vk::Fence::null(),
202            )
203        }
204        .map_err(vk_error)
205    }
206
207    pub fn present(
208        &self,
209        queue: vk::Queue,
210        image_index: u32,
211        wait_semaphore: &Semaphore,
212    ) -> Result<bool, Error> {
213        let wait_semaphores = [wait_semaphore.handle];
214        let swapchains = [self.swapchain];
215        let image_indices = [image_index];
216
217        let present_info = vk::PresentInfoKHR::default()
218            .wait_semaphores(&wait_semaphores)
219            .swapchains(&swapchains)
220            .image_indices(&image_indices);
221
222        unsafe { self.loader.queue_present(queue, &present_info) }.map_err(vk_error)
223    }
224
225    pub fn format(&self) -> vk::Format {
226        self.format
227    }
228
229    pub fn color_space(&self) -> vk::ColorSpaceKHR {
230        self.color_space
231    }
232
233    pub fn extent(&self) -> vk::Extent2D {
234        self.extent
235    }
236
237    pub fn images(&self) -> &[vk::Image] {
238        &self.images
239    }
240
241    pub fn image_views(&self) -> &[vk::ImageView] {
242        &self.image_views
243    }
244
245    pub fn destroy(&mut self, device: &Device) {
246        unsafe {
247            for view in self.image_views.drain(..) {
248                device.logical_device().destroy_image_view(view, None);
249            }
250            self.loader.destroy_swapchain(self.swapchain, None);
251        }
252    }
253}