1use 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 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 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
108unsafe 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
301pub fn get_first_srgb_surface_format(
303 surface_formats: &Vec<vk::SurfaceFormatKHR>,
304) -> Option<vk::SurfaceFormatKHR> {
305 surface_formats
306 .iter()
307 .cloned()
308 .find(|vk::SurfaceFormatKHR { format, .. }| is_format_srgb(*format))
310}
311
312pub fn get_first_linear_surface_format(
314 surface_formats: &Vec<vk::SurfaceFormatKHR>,
315) -> Option<vk::SurfaceFormatKHR> {
316 surface_formats
317 .iter()
318 .cloned()
319 .find(|vk::SurfaceFormatKHR { format, .. }| is_format_linear(*format))
321}
322
323#[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}