Skip to main content

bedrock/surface/
swapchain.rs

1use crate::{ffi_helper::slice_as_ptr_empty_null, *};
2use bedrock_vk::{self as brvk, TypedVulkanStructure};
3use derives::implements;
4
5pub trait Swapchain: VkHandle<Handle = brvk::VkSwapchainKHR> + DeviceChild {
6    /// Obtain a count of the array of presentable images associated with a swapchain
7    /// # Failures
8    /// On failure, this command returns
9    ///
10    /// * [`brvk::VK_ERROR_OUT_OF_HOST_MEMORY`]
11    /// * [`brvk::VK_ERROR_OUT_OF_DEVICE_MEMORY`]
12    #[implements]
13    #[inline]
14    fn image_count(&self) -> crate::Result<u32> {
15        unsafe {
16            crate::vkfn_wrapper::get_swapchain_image_count(self.device_transparent_ref(), self.as_transparent_ref())
17        }
18    }
19
20    /// Obtain the array of presentable images associated with a swapchain
21    /// # Failures
22    /// On failure, this command returns
23    ///
24    /// * [`brvk::VK_ERROR_OUT_OF_HOST_MEMORY`]
25    /// * [`brvk::VK_ERROR_OUT_OF_DEVICE_MEMORY`]
26    #[implements]
27    #[inline(always)]
28    fn images(&self, sink: &mut [core::mem::MaybeUninit<brvk::VkImage>]) -> crate::Result<ArrayQueryResult<u32>> {
29        unsafe {
30            crate::vkfn_wrapper::get_swapchain_images(self.device_transparent_ref(), self.as_transparent_ref(), sink)
31        }
32    }
33
34    /// Acquire full-screen exclusive mode for a swapchain.
35    /// # Failures
36    /// On failure, this command returns
37    ///
38    /// * `brvk::VK_ERROR_OUT_OF_HOST_MEMORY`
39    /// * `brvk::VK_ERROR_OUT_OF_DEVICE_MEMORY`
40    /// * `brvk::VK_ERROR_INITIALIZATION_FAILED`
41    /// * `brvk::VK_ERROR_SURFACE_LOST_KHR`
42    #[implements("VK_EXT_full_screen_exclusive")]
43    #[inline(always)]
44    fn acquire_full_screen_exclusive_mode(&self) -> crate::Result<()>
45    where
46        Self::ConcreteDevice: DeviceFullScreenExclusiveExtension,
47    {
48        unsafe {
49            self.device()
50                .acquire_full_screen_exclusive_mode(self.device_transparent_ref(), self.as_transparent_ref())
51        }
52    }
53
54    /// Release full-screen exclusive mode from a swapchain.
55    #[implements("VK_EXT_full_screen_exclusive")]
56    #[inline(always)]
57    fn release_full_screen_exclusive_mode(&self) -> crate::Result<()>
58    where
59        Self::ConcreteDevice: DeviceFullScreenExclusiveExtension,
60    {
61        unsafe {
62            self.device()
63                .release_full_screen_exclusive_mode(self.device_transparent_ref(), self.as_transparent_ref())
64        }
65    }
66}
67DerefContainerBracketImpl!(for Swapchain {});
68
69pub trait SwapchainMut: Swapchain + VkHandleMut {
70    /// Retrieve the index of the next available presentation image
71    /// # Failures
72    /// On failure, this command returns
73    ///
74    /// * `brvk::VK_ERROR_OUT_OF_HOST_MEMORY`
75    /// * `brvk::VK_ERROR_OUT_OF_DEVICE_MEMORY`
76    /// * `brvk::VK_ERROR_DEVICE_LOST`
77    /// * `brvk::VK_ERROR_OUT_OF_DATE_KHR`
78    /// * `brvk::VK_ERROR_SURFACE_LOST_KHR`
79    #[implements]
80    fn acquire_next(&mut self, timeout: Option<u64>, completion: CompletionHandlerMut) -> crate::Result<u32> {
81        let (semaphore, fence) = match completion {
82            CompletionHandlerMut::Host(f) => (None, Some(f)),
83            CompletionHandlerMut::Queue(s) => (Some(s), None),
84        };
85
86        unsafe {
87            crate::vkfn_wrapper::acquire_next_image(
88                self.device_transparent_ref(),
89                VkHandleRefMut::dangling(self.native_ptr()),
90                timeout.unwrap_or(u64::MAX),
91                semaphore,
92                fence,
93            )
94        }
95    }
96}
97DerefContainerBracketImpl!(for mut SwapchainMut {});
98
99pub trait SwapchainImageExt: Swapchain {
100    fn format(&self) -> brvk::VkFormat;
101    fn extent(&self) -> brvk::VkExtent2D;
102
103    /// Obtain the array of presentable images associated with a swapchain
104    /// # Failures
105    /// On failure, this command returns
106    ///
107    /// * `brvk::VK_ERROR_OUT_OF_HOST_MEMORY`
108    /// * `brvk::VK_ERROR_OUT_OF_DEVICE_MEMORY`
109    #[implements("alloc")]
110    fn images_alloc(&self) -> crate::Result<Vec<crate::SwapchainImage<&Self>>> {
111        let n = self.image_count()? as usize;
112        if n == 0 {
113            // no items
114            return Ok(crate::alloc::empty_sink_buffer());
115        }
116
117        let mut xs = crate::alloc::reserve(n);
118        let res = self.images(xs.spare_capacity_mut())?.assert_complete();
119        unsafe {
120            xs.set_len(res as _);
121        }
122
123        Ok(crate::alloc::collect_vec(xs.into_iter().map(move |r| {
124            let ext = self.extent();
125            crate::SwapchainImage(
126                r,
127                self,
128                self.format(),
129                brvk::VkExtent3D {
130                    width: ext.width,
131                    height: ext.height,
132                    depth: 1,
133                },
134            )
135        })))
136    }
137}
138DerefContainerBracketImpl!(for SwapchainImageExt {
139    #[inline(always)]
140    fn format(&self) -> brvk::VkFormat {
141        T::format(self)
142    }
143
144    #[inline(always)]
145    fn extent(&self) -> brvk::VkExtent2D {
146        T::extent(self)
147    }
148});
149
150#[repr(transparent)]
151#[derive(Clone)]
152pub struct SwapchainCreateInfo<'r, 'n, 'sw>(
153    brvk::VkSwapchainCreateInfoKHR,
154    #[allow(clippy::type_complexity)]
155    core::marker::PhantomData<(
156        &'r dyn VkHandle<Handle = brvk::VkSurfaceKHR>,
157        Option<&'n dyn brvk::VulkanStructure>,
158        Option<&'r [u32]>,
159        Option<&'sw dyn VkHandle<Handle = brvk::VkSwapchainKHR>>,
160    )>,
161);
162impl<'r, 'n, 'sw> SwapchainCreateInfo<'r, 'n, 'sw> {
163    #[inline]
164    pub fn new(
165        surface: &'r (impl VkHandle<Handle = brvk::VkSurfaceKHR> + ?Sized),
166        min_image_count: u32,
167        format: brvk::VkSurfaceFormatKHR,
168        extent: brvk::VkExtent2D,
169        usage: ImageUsageFlags,
170    ) -> Self {
171        Self(
172            brvk::VkSwapchainCreateInfoKHR {
173                sType: brvk::VkSwapchainCreateInfoKHR::TYPE,
174                pNext: core::ptr::null(),
175                flags: 0,
176                surface: surface.native_ptr(),
177                minImageCount: min_image_count,
178                imageFormat: format.format,
179                imageColorSpace: format.colorSpace,
180                imageExtent: extent,
181                imageArrayLayers: 1,
182                imageUsage: usage.bits(),
183                imageSharingMode: brvk::VK_SHARING_MODE_EXCLUSIVE,
184                queueFamilyIndexCount: 0,
185                pQueueFamilyIndices: core::ptr::null(),
186                preTransform: brvk::VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR,
187                compositeAlpha: brvk::VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
188                presentMode: brvk::VK_PRESENT_MODE_IMMEDIATE_KHR,
189                clipped: false as _,
190                oldSwapchain: None,
191            },
192            core::marker::PhantomData,
193        )
194    }
195
196    /// # Safety
197    ///
198    /// `raw` must be a valid `VkSwapchainCreateInfoKHR` struct.
199    pub const unsafe fn from_raw(raw: brvk::VkSwapchainCreateInfoKHR) -> Self {
200        Self(raw, core::marker::PhantomData)
201    }
202
203    pub const fn into_raw(self) -> brvk::VkSwapchainCreateInfoKHR {
204        self.0
205    }
206
207    pub const fn with_next(mut self, next: &'n (impl brvk::VulkanStructure + ?Sized)) -> Self {
208        self.0.pNext = next as *const _ as _;
209        self
210    }
211
212    pub const fn array_layers(mut self, layers: u32) -> Self {
213        self.0.imageArrayLayers = layers;
214        self
215    }
216
217    pub const fn shared(mut self, queue_families: &'r [u32]) -> Self {
218        assert!(!queue_families.is_empty(), "empty families not allowed");
219
220        self.0.imageSharingMode = brvk::VK_SHARING_MODE_CONCURRENT;
221        self.0.queueFamilyIndexCount = queue_families.len() as _;
222        self.0.pQueueFamilyIndices = slice_as_ptr_empty_null(queue_families);
223        self
224    }
225
226    pub const fn exclusive(mut self) -> Self {
227        self.0.imageSharingMode = brvk::VK_SHARING_MODE_EXCLUSIVE;
228        self.0.queueFamilyIndexCount = 0;
229        self.0.pQueueFamilyIndices = core::ptr::null();
230
231        self
232    }
233
234    /// Default: Inherit
235    pub const fn pre_transform(mut self, tf: SurfaceTransformFlags) -> Self {
236        self.0.preTransform = tf.bits();
237        self
238    }
239
240    /// Default: Inherit
241    pub const fn composite_alpha(mut self, a: CompositeAlphaFlags) -> Self {
242        self.0.compositeAlpha = a.bits();
243        self
244    }
245
246    /// Default: FIFO
247    pub const fn present_mode(mut self, mode: PresentMode) -> Self {
248        self.0.presentMode = mode as _;
249        self
250    }
251
252    /// Enables whether the Vulkan implementation is allowed to discard rendering operations
253    /// that affect regions of the surface which aren't visible
254    pub const fn enable_clip(mut self) -> Self {
255        self.0.clipped = true as _;
256        self
257    }
258
259    #[inline(always)]
260    pub fn old_swapchain(
261        mut self,
262        old_swapchain: &'sw (impl VkHandle<Handle = brvk::VkSwapchainKHR> + ?Sized),
263    ) -> Self {
264        self.0.oldSwapchain = Some(old_swapchain.native_ptr());
265        self
266    }
267}