rotex_vulkan/backend/vulkan/
swapchain.rs1use 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}