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    /// Query surface capabilities
25    pub fn capabilities(this: &Self) -> Result<vk::SurfaceCapabilitiesKHR, DriverError> {
26        let surface_ext = Device::expect_surface_ext(&this.device);
27
28        unsafe {
29            surface_ext.get_physical_device_surface_capabilities(
30                *this.device.physical_device,
31                this.surface,
32            )
33        }
34        .inspect_err(|err| warn!("unable to get surface capabilities: {err}"))
35        .or(Err(DriverError::Unsupported))
36    }
37
38    /// Create a surface from a raw window display handle.
39    ///
40    /// `device` must have been created with platform specific surface extensions enabled, acquired
41    /// through [`Device::create_display_window`].
42    #[profiling::function]
43    pub fn create(
44        device: &Arc<Device>,
45        window: &(impl HasDisplayHandle + HasWindowHandle),
46    ) -> Result<Self, DriverError> {
47        let device = Arc::clone(device);
48        let instance = Device::instance(&device);
49        let display_handle = window.display_handle().map_err(|err| {
50            warn!("{err}");
51
52            DriverError::Unsupported
53        })?;
54        let window_handle = window.window_handle().map_err(|err| {
55            warn!("{err}");
56
57            DriverError::Unsupported
58        })?;
59        let surface = unsafe {
60            create_surface(
61                Instance::entry(instance),
62                instance,
63                display_handle.as_raw(),
64                window_handle.as_raw(),
65                None,
66            )
67        }
68        .map_err(|err| {
69            warn!("Unable to create surface: {err}");
70
71            DriverError::Unsupported
72        })?;
73
74        Ok(Self { device, surface })
75    }
76
77    /// Lists the supported surface formats.
78    #[profiling::function]
79    pub fn formats(this: &Self) -> Result<Vec<vk::SurfaceFormatKHR>, DriverError> {
80        unsafe {
81            this.device
82                .surface_ext
83                .as_ref()
84                .unwrap()
85                .get_physical_device_surface_formats(*this.device.physical_device, this.surface)
86                .map_err(|err| {
87                    warn!("Unable to get surface formats: {err}");
88
89                    DriverError::Unsupported
90                })
91        }
92    }
93
94    /// Helper function to automatically select the best UNORM format, if one is available.
95    #[profiling::function]
96    pub fn linear(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
97        formats
98            .iter()
99            .find(|&&vk::SurfaceFormatKHR { format, .. }| {
100                matches!(
101                    format,
102                    vk::Format::R8G8B8A8_UNORM | vk::Format::B8G8R8A8_UNORM
103                )
104            })
105            .copied()
106    }
107
108    /// Helper function to automatically select the best UNORM format.
109    ///
110    /// **_NOTE:_** The default surface format is undefined, and although legal the results _may_
111    /// not support presentation. You should prefer to use [`Surface::linear`] and fall back to
112    /// supported values manually.
113    pub fn linear_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
114        Self::linear(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
115    }
116
117    /// Query supported presentation modes.
118    pub fn present_modes(this: &Self) -> Result<Vec<vk::PresentModeKHR>, DriverError> {
119        let surface_ext = Device::expect_surface_ext(&this.device);
120
121        unsafe {
122            surface_ext.get_physical_device_surface_present_modes(
123                *this.device.physical_device,
124                this.surface,
125            )
126        }
127        .inspect_err(|err| warn!("unable to get surface present modes: {err}"))
128        .or(Err(DriverError::Unsupported))
129    }
130
131    /// Helper function to automatically select the best sRGB format, if one is available.
132    #[profiling::function]
133    pub fn srgb(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
134        formats
135            .iter()
136            .find(
137                |&&vk::SurfaceFormatKHR {
138                     color_space,
139                     format,
140                 }| {
141                    matches!(color_space, vk::ColorSpaceKHR::SRGB_NONLINEAR)
142                        && matches!(
143                            format,
144                            vk::Format::R8G8B8A8_SRGB | vk::Format::B8G8R8A8_SRGB
145                        )
146                },
147            )
148            .copied()
149    }
150
151    /// Helper function to automatically select the best sRGB format.
152    ///
153    /// **_NOTE:_** The default surface format is undefined, and although legal the results _may_
154    /// not support presentation. You should prefer to use [`Surface::srgb`] and fall back to
155    /// supported values manually.
156    pub fn srgb_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
157        Self::srgb(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
158    }
159}
160
161impl Debug for Surface {
162    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
163        f.write_str("Surface")
164    }
165}
166
167impl Deref for Surface {
168    type Target = vk::SurfaceKHR;
169
170    fn deref(&self) -> &Self::Target {
171        &self.surface
172    }
173}
174
175impl Drop for Surface {
176    #[profiling::function]
177    fn drop(&mut self) {
178        if panicking() {
179            return;
180        }
181
182        let surface_ext = Device::expect_surface_ext(&self.device);
183
184        unsafe {
185            surface_ext.destroy_surface(self.surface, None);
186        }
187    }
188}