1 #[cfg(doc)]
2 use super::DeviceGroup;
3 use crate::prelude::*;
4 use crate::vk;
5 use crate::RawPtr;
6 use crate::{Device, Entry, Instance};
7 use std::ffi::CStr;
8 use std::mem;
9 
10 /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_swapchain.html>
11 #[derive(Clone)]
12 pub struct Swapchain {
13     handle: vk::Device,
14     fp: vk::KhrSwapchainFn,
15 }
16 
17 impl Swapchain {
18     /// # Warning
19     /// [`Instance`] functions cannot be loaded from a [`Device`] and will always panic when called:
20     /// - [`Self::get_physical_device_present_rectangles()`]
21     ///
22     /// Load this struct using an [`Instance`] instead via [`Self::new_from_instance()`] if the
23     /// above [`Instance`] function is called. This will be solved in the next breaking `ash`
24     /// release: <https://github.com/ash-rs/ash/issues/727>.
new(instance: &Instance, device: &Device) -> Self25     pub fn new(instance: &Instance, device: &Device) -> Self {
26         let handle = device.handle();
27         let fp = vk::KhrSwapchainFn::load(|name| unsafe {
28             mem::transmute(instance.get_device_proc_addr(handle, name.as_ptr()))
29         });
30         Self { handle, fp }
31     }
32 
33     /// Loads all functions on the [`Instance`] instead of [`Device`]. This incurs an extra
34     /// dispatch table for [`Device`] functions but also allows the [`Instance`] function to be
35     /// loaded instead of always panicking. See also [`Self::new()`] for more details.
36     ///
37     /// It is okay to pass [`vk::Device::null()`] when this struct is only used to call the
38     /// [`Instance`] function.
new_from_instance(entry: &Entry, instance: &Instance, device: vk::Device) -> Self39     pub fn new_from_instance(entry: &Entry, instance: &Instance, device: vk::Device) -> Self {
40         let fp = vk::KhrSwapchainFn::load(|name| unsafe {
41             mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
42         });
43         Self { handle: device, fp }
44     }
45 
46     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateSwapchainKHR.html>
47     #[inline]
create_swapchain( &self, create_info: &vk::SwapchainCreateInfoKHR, allocation_callbacks: Option<&vk::AllocationCallbacks>, ) -> VkResult<vk::SwapchainKHR>48     pub unsafe fn create_swapchain(
49         &self,
50         create_info: &vk::SwapchainCreateInfoKHR,
51         allocation_callbacks: Option<&vk::AllocationCallbacks>,
52     ) -> VkResult<vk::SwapchainKHR> {
53         let mut swapchain = mem::zeroed();
54         (self.fp.create_swapchain_khr)(
55             self.handle,
56             create_info,
57             allocation_callbacks.as_raw_ptr(),
58             &mut swapchain,
59         )
60         .result_with_success(swapchain)
61     }
62 
63     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkDestroySwapchainKHR.html>
64     #[inline]
destroy_swapchain( &self, swapchain: vk::SwapchainKHR, allocation_callbacks: Option<&vk::AllocationCallbacks>, )65     pub unsafe fn destroy_swapchain(
66         &self,
67         swapchain: vk::SwapchainKHR,
68         allocation_callbacks: Option<&vk::AllocationCallbacks>,
69     ) {
70         (self.fp.destroy_swapchain_khr)(self.handle, swapchain, allocation_callbacks.as_raw_ptr());
71     }
72 
73     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetSwapchainImagesKHR.html>
74     #[inline]
get_swapchain_images( &self, swapchain: vk::SwapchainKHR, ) -> VkResult<Vec<vk::Image>>75     pub unsafe fn get_swapchain_images(
76         &self,
77         swapchain: vk::SwapchainKHR,
78     ) -> VkResult<Vec<vk::Image>> {
79         read_into_uninitialized_vector(|count, data| {
80             (self.fp.get_swapchain_images_khr)(self.handle, swapchain, count, data)
81         })
82     }
83 
84     /// On success, returns the next image's index and whether the swapchain is suboptimal for the surface.
85     ///
86     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkAcquireNextImageKHR.html>
87     #[inline]
acquire_next_image( &self, swapchain: vk::SwapchainKHR, timeout: u64, semaphore: vk::Semaphore, fence: vk::Fence, ) -> VkResult<(u32, bool)>88     pub unsafe fn acquire_next_image(
89         &self,
90         swapchain: vk::SwapchainKHR,
91         timeout: u64,
92         semaphore: vk::Semaphore,
93         fence: vk::Fence,
94     ) -> VkResult<(u32, bool)> {
95         let mut index = 0;
96         let err_code = (self.fp.acquire_next_image_khr)(
97             self.handle,
98             swapchain,
99             timeout,
100             semaphore,
101             fence,
102             &mut index,
103         );
104         match err_code {
105             vk::Result::SUCCESS => Ok((index, false)),
106             vk::Result::SUBOPTIMAL_KHR => Ok((index, true)),
107             _ => Err(err_code),
108         }
109     }
110 
111     /// On success, returns whether the swapchain is suboptimal for the surface.
112     ///
113     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkQueuePresentKHR.html>
114     #[inline]
queue_present( &self, queue: vk::Queue, present_info: &vk::PresentInfoKHR, ) -> VkResult<bool>115     pub unsafe fn queue_present(
116         &self,
117         queue: vk::Queue,
118         present_info: &vk::PresentInfoKHR,
119     ) -> VkResult<bool> {
120         let err_code = (self.fp.queue_present_khr)(queue, present_info);
121         match err_code {
122             vk::Result::SUCCESS => Ok(false),
123             vk::Result::SUBOPTIMAL_KHR => Ok(true),
124             _ => Err(err_code),
125         }
126     }
127 
128     /// Only available since [Vulkan 1.1].
129     ///
130     /// Also available as [`DeviceGroup::get_device_group_present_capabilities()`]
131     /// when [`VK_KHR_surface`] is enabled.
132     ///
133     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetDeviceGroupPresentCapabilitiesKHR.html>
134     ///
135     /// [Vulkan 1.1]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_VERSION_1_1.html
136     /// [`VK_KHR_surface`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_surface.html
137     #[inline]
get_device_group_present_capabilities( &self, device_group_present_capabilities: &mut vk::DeviceGroupPresentCapabilitiesKHR, ) -> VkResult<()>138     pub unsafe fn get_device_group_present_capabilities(
139         &self,
140         device_group_present_capabilities: &mut vk::DeviceGroupPresentCapabilitiesKHR,
141     ) -> VkResult<()> {
142         (self.fp.get_device_group_present_capabilities_khr)(
143             self.handle,
144             device_group_present_capabilities,
145         )
146         .result()
147     }
148 
149     /// Only available since [Vulkan 1.1].
150     ///
151     /// Also available as [`DeviceGroup::get_device_group_surface_present_modes()`]
152     /// when [`VK_KHR_surface`] is enabled.
153     ///
154     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetDeviceGroupSurfacePresentModesKHR.html>
155     ///
156     /// [Vulkan 1.1]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_VERSION_1_1.html
157     /// [`VK_KHR_surface`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_surface.html
158     #[inline]
get_device_group_surface_present_modes( &self, surface: vk::SurfaceKHR, ) -> VkResult<vk::DeviceGroupPresentModeFlagsKHR>159     pub unsafe fn get_device_group_surface_present_modes(
160         &self,
161         surface: vk::SurfaceKHR,
162     ) -> VkResult<vk::DeviceGroupPresentModeFlagsKHR> {
163         let mut modes = mem::zeroed();
164         (self.fp.get_device_group_surface_present_modes_khr)(self.handle, surface, &mut modes)
165             .result_with_success(modes)
166     }
167 
168     /// Only available since [Vulkan 1.1].
169     ///
170     /// Also available as [`DeviceGroup::get_physical_device_present_rectangles()`]
171     /// when [`VK_KHR_surface`] is enabled.
172     ///
173     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPhysicalDevicePresentRectanglesKHR.html>
174     ///
175     /// [Vulkan 1.1]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_VERSION_1_1.html
176     /// [`VK_KHR_surface`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_surface.html
177     ///
178     /// # Warning
179     ///
180     /// Function will always panic unless this struct is loaded via [`Self::new_from_instance()`].
181     #[inline]
get_physical_device_present_rectangles( &self, physical_device: vk::PhysicalDevice, surface: vk::SurfaceKHR, ) -> VkResult<Vec<vk::Rect2D>>182     pub unsafe fn get_physical_device_present_rectangles(
183         &self,
184         physical_device: vk::PhysicalDevice,
185         surface: vk::SurfaceKHR,
186     ) -> VkResult<Vec<vk::Rect2D>> {
187         read_into_uninitialized_vector(|count, data| {
188             (self.fp.get_physical_device_present_rectangles_khr)(
189                 physical_device,
190                 surface,
191                 count,
192                 data,
193             )
194         })
195     }
196 
197     /// On success, returns the next image's index and whether the swapchain is suboptimal for the surface.
198     ///
199     /// Only available since [Vulkan 1.1].
200     ///
201     /// Also available as [`DeviceGroup::acquire_next_image2()`]
202     /// when [`VK_KHR_swapchain`] is enabled.
203     ///
204     /// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkAcquireNextImage2KHR.html>
205     ///
206     /// [Vulkan 1.1]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_VERSION_1_1.html
207     /// [`VK_KHR_swapchain`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_swapchain.html
208     #[inline]
acquire_next_image2( &self, acquire_info: &vk::AcquireNextImageInfoKHR, ) -> VkResult<(u32, bool)>209     pub unsafe fn acquire_next_image2(
210         &self,
211         acquire_info: &vk::AcquireNextImageInfoKHR,
212     ) -> VkResult<(u32, bool)> {
213         let mut index = 0;
214         let err_code = (self.fp.acquire_next_image2_khr)(self.handle, acquire_info, &mut index);
215         match err_code {
216             vk::Result::SUCCESS => Ok((index, false)),
217             vk::Result::SUBOPTIMAL_KHR => Ok((index, true)),
218             _ => Err(err_code),
219         }
220     }
221 
222     #[inline]
name() -> &'static CStr223     pub const fn name() -> &'static CStr {
224         vk::KhrSwapchainFn::name()
225     }
226 
227     #[inline]
fp(&self) -> &vk::KhrSwapchainFn228     pub fn fp(&self) -> &vk::KhrSwapchainFn {
229         &self.fp
230     }
231 
232     #[inline]
device(&self) -> vk::Device233     pub fn device(&self) -> vk::Device {
234         self.handle
235     }
236 }
237