bort_vk/
surface.rs

1//! Uses code from `ash-window` for surface creation from raw window handle.
2//! Original source found (here)[https://github.com/ash-rs/ash/blob/master/ash-window/src/lib.rs]
3
4use crate::{is_format_linear, is_format_srgb, Instance, PhysicalDevice, ALLOCATION_CALLBACK_NONE};
5#[cfg(feature = "raw-window-handle-06")]
6use ash::vk::{HINSTANCE, HWND};
7use ash::{extensions::khr, prelude::VkResult, vk, Entry};
8#[cfg(feature = "raw-window-handle-05")]
9use raw_window_handle_05::{RawDisplayHandle, RawWindowHandle};
10#[cfg(feature = "raw-window-handle-06")]
11use raw_window_handle_06::{RawDisplayHandle, RawWindowHandle};
12use std::{error, fmt, sync::Arc};
13
14pub struct Surface {
15    handle: vk::SurfaceKHR,
16    surface_loader: khr::Surface,
17
18    // dependencies
19    instance: Arc<Instance>,
20}
21
22impl Surface {
23    pub fn new(
24        entry: &Entry,
25        instance: Arc<Instance>,
26        raw_display_handle: RawDisplayHandle,
27        raw_window_handle: RawWindowHandle,
28    ) -> Result<Self, SurfaceCreationError> {
29        let handle = unsafe {
30            create_vk_surface(
31                entry,
32                instance.inner(),
33                raw_display_handle,
34                raw_window_handle,
35                ALLOCATION_CALLBACK_NONE,
36            )
37        }?;
38
39        let surface_loader = khr::Surface::new(&entry, instance.inner());
40
41        Ok(Self {
42            handle,
43            surface_loader,
44
45            instance,
46        })
47    }
48
49    pub fn get_physical_device_surface_support(
50        &self,
51        physical_device: &PhysicalDevice,
52        queue_family_index: u32,
53    ) -> VkResult<bool> {
54        unsafe {
55            self.surface_loader.get_physical_device_surface_support(
56                physical_device.handle(),
57                queue_family_index,
58                self.handle,
59            )
60        }
61    }
62
63    pub fn get_physical_device_surface_capabilities(
64        &self,
65        physical_device: &PhysicalDevice,
66    ) -> VkResult<vk::SurfaceCapabilitiesKHR> {
67        unsafe {
68            self.surface_loader
69                .get_physical_device_surface_capabilities(physical_device.handle(), self.handle)
70        }
71    }
72
73    pub fn get_physical_device_surface_formats(
74        &self,
75        physical_device: &PhysicalDevice,
76    ) -> VkResult<Vec<vk::SurfaceFormatKHR>> {
77        unsafe {
78            self.surface_loader
79                .get_physical_device_surface_formats(physical_device.handle(), self.handle)
80        }
81    }
82
83    pub fn get_physical_device_surface_present_modes(
84        &self,
85        physical_device: &PhysicalDevice,
86    ) -> VkResult<Vec<vk::PresentModeKHR>> {
87        unsafe {
88            self.surface_loader
89                .get_physical_device_surface_present_modes(physical_device.handle(), self.handle)
90        }
91    }
92
93    // Getters
94
95    pub fn handle(&self) -> vk::SurfaceKHR {
96        self.handle
97    }
98
99    pub fn surface_loader(&self) -> &khr::Surface {
100        &self.surface_loader
101    }
102
103    pub fn instance(&self) -> &Arc<Instance> {
104        &self.instance
105    }
106}
107
108/// Create a surface from a raw surface handle.
109///
110/// _Note: this function was copied from [ash](https://github.com/ash-rs/ash) to allow for better
111/// dependency control._
112///
113/// `instance` must have created with platform specific surface extensions enabled, acquired
114/// through [`enumerate_required_extensions()`].
115///
116/// # Safety
117///
118/// There is a [parent/child relation] between [`Instance`] and [`Entry`], and the resulting
119/// [`vk::SurfaceKHR`].  The application must not [destroy][Instance::destroy_instance()] these
120/// parent objects before first [destroying][khr::Surface::destroy_surface()] the returned
121/// [`vk::SurfaceKHR`] child object.  [`vk::SurfaceKHR`] does _not_ implement [drop][drop()]
122/// semantics and can only be destroyed via [`destroy_surface()`][khr::Surface::destroy_surface()].
123///
124/// See the [`Entry::create_instance()`] documentation for more destruction ordering rules on
125/// [`Instance`].
126///
127/// The window represented by `window_handle` must be associated with the display connection
128/// in `display_handle`.
129///
130/// `window_handle` and `display_handle` must be associated with a valid window and display
131/// connection, which must not be destroyed for the lifetime of the returned [`vk::SurfaceKHR`].
132///
133/// [parent/child relation]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#fundamentals-objectmodel-lifetime
134unsafe fn create_vk_surface(
135    entry: &Entry,
136    instance: &ash::Instance,
137    display_handle: RawDisplayHandle,
138    window_handle: RawWindowHandle,
139    allocation_callbacks: Option<&vk::AllocationCallbacks>,
140) -> Result<vk::SurfaceKHR, SurfaceCreationError> {
141    match (display_handle, window_handle) {
142        (RawDisplayHandle::Windows(_), RawWindowHandle::Win32(window)) => {
143            #[cfg(feature = "raw-window-handle-05")]
144            let hinstance = window.hinstance;
145            #[cfg(feature = "raw-window-handle-06")]
146            let hinstance = window
147                .hinstance
148                .ok_or(SurfaceCreationError::NoWin32HINSTANCE)?
149                .get() as HINSTANCE;
150
151            #[cfg(feature = "raw-window-handle-05")]
152            let hwnd = window.hwnd;
153            #[cfg(feature = "raw-window-handle-06")]
154            let hwnd = window.hwnd.get() as HWND;
155
156            let surface_desc = vk::Win32SurfaceCreateInfoKHR::builder()
157                .hinstance(hinstance)
158                .hwnd(hwnd);
159            let surface_fn = khr::Win32Surface::new(entry, instance);
160            let surface_handle =
161                surface_fn.create_win32_surface(&surface_desc, allocation_callbacks)?;
162            Ok(surface_handle)
163        }
164
165        (RawDisplayHandle::Wayland(display), RawWindowHandle::Wayland(window)) => {
166            #[cfg(feature = "raw-window-handle-05")]
167            let display_wl = display.display;
168            #[cfg(feature = "raw-window-handle-06")]
169            let display_wl = display.display.as_ptr();
170
171            #[cfg(feature = "raw-window-handle-05")]
172            let surface_wl = window.surface;
173            #[cfg(feature = "raw-window-handle-06")]
174            let surface_wl = window.surface.as_ptr();
175
176            let surface_desc = vk::WaylandSurfaceCreateInfoKHR::builder()
177                .display(display_wl)
178                .surface(surface_wl);
179            let surface_fn = khr::WaylandSurface::new(entry, instance);
180            let surface_handle =
181                surface_fn.create_wayland_surface(&surface_desc, allocation_callbacks)?;
182            Ok(surface_handle)
183        }
184
185        (RawDisplayHandle::Xlib(display), RawWindowHandle::Xlib(window)) => {
186            #[cfg(feature = "raw-window-handle-05")]
187            let display_x = display.display;
188            #[cfg(feature = "raw-window-handle-06")]
189            let display_x = display
190                .display
191                .ok_or(SurfaceCreationError::NoXlibDisplayPointer)?
192                .as_ptr();
193
194            let surface_desc = vk::XlibSurfaceCreateInfoKHR::builder()
195                .dpy(display_x.cast())
196                .window(window.window);
197            let surface_fn = khr::XlibSurface::new(entry, instance);
198            let surface_handle =
199                surface_fn.create_xlib_surface(&surface_desc, allocation_callbacks)?;
200            Ok(surface_handle)
201        }
202
203        (RawDisplayHandle::Xcb(display), RawWindowHandle::Xcb(window)) => {
204            #[cfg(feature = "raw-window-handle-05")]
205            let connection_xcb = display.connection;
206            #[cfg(feature = "raw-window-handle-06")]
207            let connection_xcb = display
208                .connection
209                .ok_or(SurfaceCreationError::NoXcbConnectionPointer)?
210                .as_ptr();
211
212            #[cfg(feature = "raw-window-handle-05")]
213            let window_xcb = window.window;
214            #[cfg(feature = "raw-window-handle-06")]
215            let window_xcb = window.window.get();
216
217            let surface_desc = vk::XcbSurfaceCreateInfoKHR::builder()
218                .connection(connection_xcb)
219                .window(window_xcb);
220            let surface_fn = khr::XcbSurface::new(entry, instance);
221            let surface_handle =
222                surface_fn.create_xcb_surface(&surface_desc, allocation_callbacks)?;
223            Ok(surface_handle)
224        }
225
226        (RawDisplayHandle::Android(_), RawWindowHandle::AndroidNdk(window)) => {
227            #[cfg(feature = "raw-window-handle-05")]
228            let window_android = window.a_native_window;
229            #[cfg(feature = "raw-window-handle-06")]
230            let window_android = window.a_native_window.as_ptr();
231
232            let surface_desc = vk::AndroidSurfaceCreateInfoKHR::builder().window(window_android);
233            let surface_fn = khr::AndroidSurface::new(entry, instance);
234            let surface_handle =
235                surface_fn.create_android_surface(&surface_desc, allocation_callbacks)?;
236            Ok(surface_handle)
237        }
238
239        #[cfg(target_os = "macos")]
240        (RawDisplayHandle::AppKit(_), RawWindowHandle::AppKit(window)) => {
241            use ash::extensions::ext::MetalSurface;
242            #[cfg(feature = "raw-window-handle-05")]
243            use raw_window_metal_03::{appkit, Layer};
244            #[cfg(feature = "raw-window-handle-06")]
245            use raw_window_metal_04::{appkit, Layer};
246
247            #[cfg(feature = "raw-window-handle-05")]
248            let layer = match appkit::metal_layer_from_handle(window) {
249                Layer::Existing(layer) | Layer::Allocated(layer) => layer.cast(),
250                Layer::None => return Err(vk::Result::ERROR_INITIALIZATION_FAILED.into()),
251            };
252            #[cfg(feature = "raw-window-handle-06")]
253            let layer = match appkit::metal_layer_from_handle(window) {
254                Layer::Existing(layer) | Layer::Allocated(layer) => layer.cast(),
255            };
256
257            let surface_desc = vk::MetalSurfaceCreateInfoEXT::builder().layer(&*layer);
258            let surface_fn = MetalSurface::new(entry, instance);
259            let surface_handle =
260                surface_fn.create_metal_surface(&surface_desc, allocation_callbacks)?;
261            Ok(surface_handle)
262        }
263
264        #[cfg(target_os = "ios")]
265        (RawDisplayHandle::UiKit(_), RawWindowHandle::UiKit(window)) => {
266            #[cfg(feature = "raw-window-handle-05")]
267            use raw_window_metal_03::{uikit, Layer};
268            #[cfg(feature = "raw-window-handle-06")]
269            use raw_window_metal_04::{uikit, Layer};
270
271            #[cfg(feature = "raw-window-handle-05")]
272            let layer = match uikit::metal_layer_from_handle(window) {
273                Layer::Existing(layer) | Layer::Allocated(layer) => layer.cast(),
274                Layer::None => return Err(vk::Result::ERROR_INITIALIZATION_FAILED.into()),
275            };
276            #[cfg(feature = "raw-window-handle-06")]
277            let layer = match uikit::metal_layer_from_handle(window) {
278                Layer::Existing(layer) | Layer::Allocated(layer) => layer.cast(),
279            };
280
281            let surface_desc = vk::MetalSurfaceCreateInfoEXT::builder().layer(&*layer);
282            let surface_fn = ext::MetalSurface::new(entry, instance);
283            let surface_handle =
284                surface_fn.create_metal_surface(&surface_desc, allocation_callbacks)?;
285            Ok(surface_handle)
286        }
287
288        _ => Err(SurfaceCreationError::UnsupportedDisplaySystem()),
289    }
290}
291
292impl Drop for Surface {
293    fn drop(&mut self) {
294        unsafe {
295            self.surface_loader
296                .destroy_surface(self.handle, ALLOCATION_CALLBACK_NONE)
297        };
298    }
299}
300
301/// Returns the first surface format with a linear image format in the vec. Returns `None` is there's none.
302pub fn get_first_srgb_surface_format(
303    surface_formats: &Vec<vk::SurfaceFormatKHR>,
304) -> Option<vk::SurfaceFormatKHR> {
305    surface_formats
306        .iter()
307        .cloned()
308        // use the first SRGB format we find
309        .find(|vk::SurfaceFormatKHR { format, .. }| is_format_srgb(*format))
310}
311
312/// Returns the first surface format with a linear image format in the vec. Returns `None` is there's none.
313pub fn get_first_linear_surface_format(
314    surface_formats: &Vec<vk::SurfaceFormatKHR>,
315) -> Option<vk::SurfaceFormatKHR> {
316    surface_formats
317        .iter()
318        .cloned()
319        // use the first linear format we find
320        .find(|vk::SurfaceFormatKHR { format, .. }| is_format_linear(*format))
321}
322
323// ~~ Errors ~~
324
325#[derive(Clone, Copy, Debug)]
326pub enum SurfaceCreationError {
327    VkResult(vk::Result),
328    NoXcbConnectionPointer,
329    NoXlibDisplayPointer,
330    NoWin32HINSTANCE,
331    UnsupportedDisplaySystem(),
332}
333
334impl fmt::Display for SurfaceCreationError {
335    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336        match self {
337            Self::VkResult(e) => write!(f, "{}", e),
338            Self::NoXcbConnectionPointer => write!(
339                f,
340                "the XCB display handle is missing a valid xcb_connection_t* pointer which is required
341                to create a surface"
342            ),
343            Self::NoXlibDisplayPointer => write!(
344                f,
345                "the X11 display handle is missing a valid Display* pointer which is required
346                to create a surface"
347            ),
348            Self::NoWin32HINSTANCE => write!(
349                f,
350                "the Win32 window handle is missing a valid HINSTANCE which is required
351                to create a surface"
352            ),
353            Self::UnsupportedDisplaySystem() => write!(
354                f,
355                "the display and window handles represent a windowing system that is currently unsupported."
356            )
357        }
358    }
359}
360
361impl error::Error for SurfaceCreationError {}
362
363impl From<vk::Result> for SurfaceCreationError {
364    fn from(res: vk::Result) -> Self {
365        Self::VkResult(res)
366    }
367}