screen_13/driver/
surface.rs

1//! Native platform window surface types.
2
3use {
4    super::{DriverError, Instance, device::Device},
5    ash::vk,
6    ash_window::create_surface,
7    log::warn,
8    raw_window_handle::{HasDisplayHandle, HasWindowHandle},
9    std::{
10        fmt::{Debug, Formatter},
11        ops::Deref,
12        sync::Arc,
13        thread::panicking,
14    },
15};
16
17/// Smart pointer handle to a [`vk::SurfaceKHR`] object.
18pub struct Surface {
19    device: Arc<Device>,
20    surface: vk::SurfaceKHR,
21}
22
23impl Surface {
24    /// Create a surface from a raw window display handle.
25    ///
26    /// `device` must have been created with platform specific surface extensions enabled, acquired
27    /// through [`Device::create_display_window`].
28    #[profiling::function]
29    pub fn create(
30        device: &Arc<Device>,
31        window: &(impl HasDisplayHandle + HasWindowHandle),
32    ) -> Result<Self, DriverError> {
33        let device = Arc::clone(device);
34        let instance = Device::instance(&device);
35        let display_handle = window.display_handle().map_err(|err| {
36            warn!("{err}");
37
38            DriverError::Unsupported
39        })?;
40        let window_handle = window.window_handle().map_err(|err| {
41            warn!("{err}");
42
43            DriverError::Unsupported
44        })?;
45        let surface = unsafe {
46            create_surface(
47                Instance::entry(instance),
48                instance,
49                display_handle.as_raw(),
50                window_handle.as_raw(),
51                None,
52            )
53        }
54        .map_err(|err| {
55            warn!("Unable to create surface: {err}");
56
57            DriverError::Unsupported
58        })?;
59
60        Ok(Self { device, surface })
61    }
62
63    /// Lists the supported surface formats.
64    #[profiling::function]
65    pub fn formats(this: &Self) -> Result<Vec<vk::SurfaceFormatKHR>, DriverError> {
66        unsafe {
67            this.device
68                .surface_ext
69                .as_ref()
70                .unwrap()
71                .get_physical_device_surface_formats(*this.device.physical_device, this.surface)
72                .map_err(|err| {
73                    warn!("Unable to get surface formats: {err}");
74
75                    DriverError::Unsupported
76                })
77        }
78    }
79
80    /// Helper function to automatically select the best UNORM format, if one is available.
81    #[profiling::function]
82    pub fn linear(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
83        formats
84            .iter()
85            .find(|&&vk::SurfaceFormatKHR { format, .. }| {
86                matches!(
87                    format,
88                    vk::Format::R8G8B8A8_UNORM | vk::Format::B8G8R8A8_UNORM
89                )
90            })
91            .copied()
92    }
93
94    /// Helper function to automatically select the best UNORM format.
95    ///
96    /// **_NOTE:_** The default surface format is undefined, and although legal the results _may_
97    /// not support presentation. You should prefer to use [`Surface::linear`] and fall back to
98    /// supported values manually.
99    pub fn linear_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
100        Self::linear(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
101    }
102
103    /// Helper function to automatically select the best sRGB format, if one is available.
104    #[profiling::function]
105    pub fn srgb(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
106        formats
107            .iter()
108            .find(
109                |&&vk::SurfaceFormatKHR {
110                     color_space,
111                     format,
112                 }| {
113                    matches!(color_space, vk::ColorSpaceKHR::SRGB_NONLINEAR)
114                        && matches!(
115                            format,
116                            vk::Format::R8G8B8A8_SRGB | vk::Format::B8G8R8A8_SRGB
117                        )
118                },
119            )
120            .copied()
121    }
122
123    /// Helper function to automatically select the best sRGB format.
124    ///
125    /// **_NOTE:_** The default surface format is undefined, and although legal the results _may_
126    /// not support presentation. You should prefer to use [`Surface::srgb`] and fall back to
127    /// supported values manually.
128    pub fn srgb_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
129        Self::srgb(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
130    }
131}
132
133impl Debug for Surface {
134    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
135        f.write_str("Surface")
136    }
137}
138
139impl Deref for Surface {
140    type Target = vk::SurfaceKHR;
141
142    fn deref(&self) -> &Self::Target {
143        &self.surface
144    }
145}
146
147impl Drop for Surface {
148    #[profiling::function]
149    fn drop(&mut self) {
150        if panicking() {
151            return;
152        }
153
154        let surface_ext = Device::expect_surface_ext(&self.device);
155
156        unsafe {
157            surface_ext.destroy_surface(self.surface, None);
158        }
159    }
160}