demo_vk/graphics/vulkan/swapchain/
mod.rs

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