demo_vk/graphics/vulkan/swapchain/
mod.rs

1mod settings;
2
3use {
4    crate::{
5        graphics::vulkan::{raii, VulkanContext},
6        unwrap_here,
7    },
8    anyhow::{anyhow, Context, Result},
9    ash::vk,
10    std::sync::Arc,
11};
12
13#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
14pub enum AcquireImageStatus {
15    ImageAcquired(u32),
16    SwapchainNeedsRebuild,
17}
18
19#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
20pub enum PresentImageStatus {
21    Queued,
22    SwapchainNeedsRebuild,
23}
24
25/// The Vulkan swapchain and associated resources.
26pub struct Swapchain {
27    swapchain: Arc<raii::Swapchain>,
28    extent: vk::Extent2D,
29    format: vk::SurfaceFormatKHR,
30    images: Vec<vk::Image>,
31    image_views: Vec<raii::ImageView>,
32    cxt: Arc<VulkanContext>,
33}
34
35impl Swapchain {
36    /// Creates a new Vulkan swapchain.
37    pub fn new(
38        cxt: Arc<VulkanContext>,
39        framebuffer_size: (u32, u32),
40        previous_swapchain: Option<vk::SwapchainKHR>,
41    ) -> Result<Self> {
42        let (swapchain, extent, format) = unwrap_here!(
43            "Create swapchain",
44            settings::create_swapchain(
45                &cxt,
46                framebuffer_size,
47                previous_swapchain,
48            )
49        );
50
51        let images = unwrap_here!("Get swapchain images", unsafe {
52            swapchain.ext.get_swapchain_images(swapchain.raw)
53        });
54        let mut image_views = vec![];
55        for (index, image) in images.iter().enumerate() {
56            let create_info = vk::ImageViewCreateInfo {
57                image: *image,
58                view_type: vk::ImageViewType::TYPE_2D,
59                format: format.format,
60                components: vk::ComponentMapping::default(),
61                subresource_range: vk::ImageSubresourceRange {
62                    aspect_mask: vk::ImageAspectFlags::COLOR,
63                    base_mip_level: 0,
64                    level_count: 1,
65                    base_array_layer: 0,
66                    layer_count: 1,
67                },
68                ..Default::default()
69            };
70            let image_view = unwrap_here!(
71                format!("Create swapchain image view [{}]", index),
72                raii::ImageView::new(
73                    format!("Swapchain Image [{}]", index),
74                    cxt.device.clone(),
75                    &create_info,
76                )
77            );
78            image_views.push(image_view);
79        }
80
81        Ok(Self {
82            swapchain,
83            extent,
84            format,
85            images,
86            image_views,
87            cxt,
88        })
89    }
90
91    /// Returns the non-owning Vulkan swapchain handle.
92    pub fn raw(&self) -> vk::SwapchainKHR {
93        self.swapchain.raw
94    }
95
96    /// Returns the Swapchain's current extent.
97    pub fn extent(&self) -> vk::Extent2D {
98        self.extent
99    }
100
101    /// Returns a scissor rect for the full swapchain extent.
102    pub fn scissor(&self) -> vk::Rect2D {
103        vk::Rect2D {
104            offset: vk::Offset2D { x: 0, y: 0 },
105            extent: self.extent,
106        }
107    }
108
109    pub fn viewport(&self) -> vk::Viewport {
110        vk::Viewport {
111            x: 0.0,
112            y: 0.0,
113            width: self.extent.width as f32,
114            height: self.extent.height as f32,
115            min_depth: 0.0,
116            max_depth: 1.0,
117        }
118    }
119
120    /// Returns the Swapchain's image format.
121    pub fn format(&self) -> vk::Format {
122        self.format.format
123    }
124
125    /// Returns the Swapchain's image handles.
126    pub fn images(&self) -> &[vk::Image] {
127        &self.images
128    }
129
130    /// Returns the Swapchain's image views.
131    ///
132    /// Views are paired 1-1 with images of the same index.
133    pub fn image_views(&self) -> &[raii::ImageView] {
134        &self.image_views
135    }
136
137    /// Acquires the index for the next swapchain image.
138    ///
139    /// * `image_ready_semaphore` - A Vulkan semaphore to signal when the
140    ///   swapchain image is ready. This can be `vk::Semaphore::null()` if not
141    ///   required.
142    pub fn acquire_image(
143        &self,
144        image_ready_semaphore: vk::Semaphore,
145    ) -> Result<AcquireImageStatus> {
146        let result = unsafe {
147            self.swapchain.ext.acquire_next_image(
148                self.swapchain.raw,
149                u64::MAX,
150                image_ready_semaphore,
151                vk::Fence::null(),
152            )
153        };
154        match result {
155            Ok((index, false)) => Ok(AcquireImageStatus::ImageAcquired(index)),
156            Ok((_, true)) => {
157                // true indicates that the swapchain is suboptimal
158                Ok(AcquireImageStatus::SwapchainNeedsRebuild)
159            }
160            Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => {
161                Ok(AcquireImageStatus::SwapchainNeedsRebuild)
162            }
163            Err(err) => {
164                Err(anyhow!(err)).context("Unable to acquire swapchain image!")
165            }
166        }
167    }
168
169    /// Presents the swapchain image.
170    ///
171    /// * `wait_semaphore` - Image presentation waits for the semaphore to be
172    ///   signalled.
173    /// * `image_index` - The index of the swapchain image being presented. This
174    ///   must come from a prior call to [Self::acquire_image].
175    pub fn present_image(
176        &self,
177        wait_semaphore: vk::Semaphore,
178        image_index: u32,
179    ) -> Result<PresentImageStatus> {
180        let present_info = vk::PresentInfoKHR {
181            wait_semaphore_count: 1,
182            p_wait_semaphores: &wait_semaphore,
183            swapchain_count: 1,
184            p_swapchains: &self.swapchain.raw,
185            p_image_indices: &image_index,
186            ..Default::default()
187        };
188        let result = unsafe {
189            self.swapchain
190                .ext
191                .queue_present(self.cxt.graphics_queue, &present_info)
192        };
193        match result {
194            Ok(false) => Ok(PresentImageStatus::Queued),
195            Ok(true) => Ok(PresentImageStatus::SwapchainNeedsRebuild),
196            Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => {
197                Ok(PresentImageStatus::SwapchainNeedsRebuild)
198            }
199            Err(err) => Err(err).context("Unable to present swapchain image!"),
200        }
201    }
202}
203
204impl std::fmt::Debug for Swapchain {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        f.debug_struct("Swapchain")
207            .field("swapchain", &self.swapchain)
208            .field("extent", &self.extent)
209            .field("format", &self.format)
210            .field("images", &self.images)
211            .field("image_views", &self.image_views)
212            .finish()
213    }
214}