vk_graph/driver/
surface.rs1use {
4 super::{DriverError, device::Device, instance::Instance},
5 ash::vk,
6 ash_window::create_surface,
7 log::warn,
8 raw_window_handle::{HasDisplayHandle, HasWindowHandle},
9 std::{
10 fmt::{Debug, Formatter},
11 thread::panicking,
12 },
13};
14
15#[read_only::cast]
17pub struct Surface {
18 pub device: Device,
22
23 pub handle: vk::SurfaceKHR,
27}
28
29impl Surface {
30 pub fn capabilities(&self) -> Result<vk::SurfaceCapabilitiesKHR, DriverError> {
32 let surface_ext = Device::expect_surface_ext(&self.device);
33
34 unsafe {
35 surface_ext.get_physical_device_surface_capabilities(
36 self.device.physical_device.handle,
37 self.handle,
38 )
39 }
40 .map_err(|err| {
41 warn!("unable to get surface capabilities: {err}");
42
43 DriverError::Unsupported
44 })
45 }
46
47 #[profiling::function]
51 pub fn create(
52 device: &Device,
53 display: impl HasDisplayHandle,
54 window: impl HasWindowHandle,
55 ) -> Result<Self, DriverError> {
56 let device = device.clone();
57
58 let display_handle = display.display_handle().map_err(|err| {
59 warn!("unable to get display handle: {err}");
60
61 DriverError::Unsupported
62 })?;
63 let window_handle = window.window_handle().map_err(|err| {
64 warn!("unable to get window handle: {err}");
65
66 DriverError::Unsupported
67 })?;
68
69 let handle = unsafe {
70 create_surface(
71 Instance::entry(&device.physical_device.instance),
72 &device.physical_device.instance,
73 display_handle.as_raw(),
74 window_handle.as_raw(),
75 None,
76 )
77 }
78 .map_err(|err| {
79 warn!("unable to create surface: {err}");
80
81 DriverError::Unsupported
82 })?;
83
84 Ok(Self { device, handle })
85 }
86
87 #[profiling::function]
89 pub fn formats(&self) -> Result<Vec<vk::SurfaceFormatKHR>, DriverError> {
90 let surface_ext = Device::expect_surface_ext(&self.device);
91
92 unsafe {
93 surface_ext.get_physical_device_surface_formats(
94 self.device.physical_device.handle,
95 self.handle,
96 )
97 }
98 .map_err(|err| {
99 warn!("unable to get surface formats: {err}");
100
101 DriverError::Unsupported
102 })
103 }
104
105 #[profiling::function]
107 pub fn linear(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
108 formats
109 .iter()
110 .find(|&&vk::SurfaceFormatKHR { format, .. }| {
111 matches!(
112 format,
113 vk::Format::R8G8B8A8_UNORM | vk::Format::B8G8R8A8_UNORM
114 )
115 })
116 .copied()
117 }
118
119 pub fn linear_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
125 Self::linear(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
126 }
127
128 pub fn physical_device_support(&self, queue_family_index: u32) -> Result<bool, DriverError> {
130 let surface_ext = Device::expect_surface_ext(&self.device);
131
132 unsafe {
133 surface_ext.get_physical_device_surface_support(
134 self.device.physical_device.handle,
135 queue_family_index,
136 self.handle,
137 )
138 }
139 .map_err(|err| {
140 warn!("unable to get physical device support: {err}");
141
142 match err {
143 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
144 DriverError::OutOfMemory
145 }
146 vk::Result::ERROR_SURFACE_LOST_KHR => DriverError::InvalidData,
147 _ => DriverError::Unsupported,
148 }
149 })
150 }
151
152 pub fn present_modes(&self) -> Result<Vec<vk::PresentModeKHR>, DriverError> {
154 let surface_ext = Device::expect_surface_ext(&self.device);
155
156 unsafe {
157 surface_ext.get_physical_device_surface_present_modes(
158 self.device.physical_device.handle,
159 self.handle,
160 )
161 }
162 .map_err(|err| {
163 warn!("unable to get present modes: {err}");
164
165 DriverError::Unsupported
166 })
167 }
168
169 #[profiling::function]
171 pub fn srgb(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
172 formats
173 .iter()
174 .find(
175 |&&vk::SurfaceFormatKHR {
176 color_space,
177 format,
178 }| {
179 matches!(color_space, vk::ColorSpaceKHR::SRGB_NONLINEAR)
180 && matches!(
181 format,
182 vk::Format::R8G8B8A8_SRGB | vk::Format::B8G8R8A8_SRGB
183 )
184 },
185 )
186 .copied()
187 }
188
189 pub fn srgb_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
195 Self::srgb(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
196 }
197}
198
199impl Debug for Surface {
200 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
201 f.write_str("Surface")
202 }
203}
204
205impl Drop for Surface {
206 #[profiling::function]
207 fn drop(&mut self) {
208 if panicking() {
209 return;
210 }
211
212 let surface_ext = Device::expect_surface_ext(&self.device);
213
214 unsafe {
215 surface_ext.destroy_surface(self.handle, None);
216 }
217 }
218}
219
220impl Eq for Surface {}
221
222impl PartialEq for Surface {
223 fn eq(&self, other: &Self) -> bool {
224 self.handle == other.handle
225 }
226}
227
228#[cfg(test)]
229mod test {
230 use super::Surface;
231 use ash::vk;
232
233 #[test]
234 fn linear_prefers_known_unorm_formats() {
235 let formats = [
236 vk::SurfaceFormatKHR {
237 format: vk::Format::R8G8B8A8_SRGB,
238 ..Default::default()
239 },
240 vk::SurfaceFormatKHR {
241 format: vk::Format::R8G8B8A8_UNORM,
242 ..Default::default()
243 },
244 ];
245
246 assert_eq!(
247 Surface::linear(&formats).unwrap().format,
248 vk::Format::R8G8B8A8_UNORM
249 );
250 }
251
252 #[test]
253 fn linear_or_default_falls_back_to_first_format() {
254 let formats = [vk::SurfaceFormatKHR {
255 format: vk::Format::R16G16B16A16_SFLOAT,
256 ..Default::default()
257 }];
258
259 assert_eq!(
260 Surface::linear_or_default(&formats).format,
261 vk::Format::R16G16B16A16_SFLOAT
262 );
263 }
264
265 #[test]
266 fn srgb_prefers_known_srgb_formats() {
267 let formats = [
268 vk::SurfaceFormatKHR {
269 color_space: vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT,
270 format: vk::Format::B8G8R8A8_SRGB,
271 },
272 vk::SurfaceFormatKHR {
273 color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR,
274 format: vk::Format::R8G8B8A8_SRGB,
275 },
276 ];
277
278 assert_eq!(
279 Surface::srgb(&formats).unwrap().format,
280 vk::Format::R8G8B8A8_SRGB
281 );
282 }
283
284 #[test]
285 fn srgb_or_default_falls_back_to_first_format() {
286 let formats = [vk::SurfaceFormatKHR {
287 color_space: vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT,
288 format: vk::Format::R16G16B16A16_SFLOAT,
289 }];
290
291 assert_eq!(
292 Surface::srgb_or_default(&formats).format,
293 vk::Format::R16G16B16A16_SFLOAT
294 );
295 }
296}