ash_window/
lib.rs

1#![warn(trivial_casts, trivial_numeric_casts, unused_qualifications)]
2
3use std::os::raw::c_char;
4
5use ash::{
6    ext::metal_surface,
7    khr::{android_surface, surface, wayland_surface, win32_surface, xcb_surface, xlib_surface},
8    prelude::*,
9    vk, Entry, Instance,
10};
11use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
12
13/// Create a surface from a raw display and window handle.
14///
15/// `instance` must have created with platform specific surface extensions enabled, acquired
16/// through [`enumerate_required_extensions()`].
17///
18/// # Safety
19///
20/// There is a [parent/child relation] between [`Instance`] and [`Entry`], and the resulting
21/// [`vk::SurfaceKHR`].  The application must not [destroy][Instance::destroy_instance()] these
22/// parent objects before first [destroying][surface::Instance::destroy_surface()] the returned
23/// [`vk::SurfaceKHR`] child object.  [`vk::SurfaceKHR`] does _not_ implement [drop][drop()]
24/// semantics and can only be destroyed via [`destroy_surface()`][surface::Instance::destroy_surface()].
25///
26/// See the [`Entry::create_instance()`] documentation for more destruction ordering rules on
27/// [`Instance`].
28///
29/// The window represented by `window_handle` must be associated with the display connection
30/// in `display_handle`.
31///
32/// `window_handle` and `display_handle` must be associated with a valid window and display
33/// connection, which must not be destroyed for the lifetime of the returned [`vk::SurfaceKHR`].
34///
35/// [parent/child relation]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#fundamentals-objectmodel-lifetime
36pub unsafe fn create_surface(
37    entry: &Entry,
38    instance: &Instance,
39    display_handle: RawDisplayHandle,
40    window_handle: RawWindowHandle,
41    allocation_callbacks: Option<&vk::AllocationCallbacks<'_>>,
42) -> VkResult<vk::SurfaceKHR> {
43    match (display_handle, window_handle) {
44        (RawDisplayHandle::Windows(_), RawWindowHandle::Win32(window)) => {
45            let surface_desc = vk::Win32SurfaceCreateInfoKHR::default()
46                .hwnd(window.hwnd.get())
47                .hinstance(
48                    window
49                        .hinstance
50                        .ok_or(vk::Result::ERROR_INITIALIZATION_FAILED)?
51                        .get(),
52                );
53            let surface_fn = win32_surface::Instance::new(entry, instance);
54            surface_fn.create_win32_surface(&surface_desc, allocation_callbacks)
55        }
56
57        (RawDisplayHandle::Wayland(display), RawWindowHandle::Wayland(window)) => {
58            let surface_desc = vk::WaylandSurfaceCreateInfoKHR::default()
59                .display(display.display.as_ptr())
60                .surface(window.surface.as_ptr());
61            let surface_fn = wayland_surface::Instance::new(entry, instance);
62            surface_fn.create_wayland_surface(&surface_desc, allocation_callbacks)
63        }
64
65        (RawDisplayHandle::Xlib(display), RawWindowHandle::Xlib(window)) => {
66            let surface_desc = vk::XlibSurfaceCreateInfoKHR::default()
67                .dpy(
68                    display
69                        .display
70                        .ok_or(vk::Result::ERROR_INITIALIZATION_FAILED)?
71                        .as_ptr(),
72                )
73                .window(window.window);
74            let surface_fn = xlib_surface::Instance::new(entry, instance);
75            surface_fn.create_xlib_surface(&surface_desc, allocation_callbacks)
76        }
77
78        (RawDisplayHandle::Xcb(display), RawWindowHandle::Xcb(window)) => {
79            let surface_desc = vk::XcbSurfaceCreateInfoKHR::default()
80                .connection(
81                    display
82                        .connection
83                        .ok_or(vk::Result::ERROR_INITIALIZATION_FAILED)?
84                        .as_ptr(),
85                )
86                .window(window.window.get());
87            let surface_fn = xcb_surface::Instance::new(entry, instance);
88            surface_fn.create_xcb_surface(&surface_desc, allocation_callbacks)
89        }
90
91        (RawDisplayHandle::Android(_), RawWindowHandle::AndroidNdk(window)) => {
92            let surface_desc =
93                vk::AndroidSurfaceCreateInfoKHR::default().window(window.a_native_window.as_ptr());
94            let surface_fn = android_surface::Instance::new(entry, instance);
95            surface_fn.create_android_surface(&surface_desc, allocation_callbacks)
96        }
97
98        #[cfg(target_os = "macos")]
99        (RawDisplayHandle::AppKit(_), RawWindowHandle::AppKit(window)) => {
100            use raw_window_metal::{appkit, Layer};
101
102            let layer = match appkit::metal_layer_from_handle(window) {
103                Layer::Existing(layer) | Layer::Allocated(layer) => layer.cast(),
104            };
105
106            let surface_desc = vk::MetalSurfaceCreateInfoEXT::default().layer(&*layer);
107            let surface_fn = metal_surface::Instance::new(entry, instance);
108            surface_fn.create_metal_surface(&surface_desc, allocation_callbacks)
109        }
110
111        #[cfg(target_os = "ios")]
112        (RawDisplayHandle::UiKit(_), RawWindowHandle::UiKit(window)) => {
113            use raw_window_metal::{uikit, Layer};
114
115            let layer = match uikit::metal_layer_from_handle(window) {
116                Layer::Existing(layer) | Layer::Allocated(layer) => layer.cast(),
117            };
118
119            let surface_desc = vk::MetalSurfaceCreateInfoEXT::default().layer(&*layer);
120            let surface_fn = metal_surface::Instance::new(entry, instance);
121            surface_fn.create_metal_surface(&surface_desc, allocation_callbacks)
122        }
123
124        _ => Err(vk::Result::ERROR_EXTENSION_NOT_PRESENT),
125    }
126}
127
128/// Query the required instance extensions for creating a surface from a raw display handle.
129///
130/// This [`RawDisplayHandle`] can typically be acquired from a window, but is usually also
131/// accessible earlier through an "event loop" concept to allow querying required instance
132/// extensions and creation of a compatible Vulkan instance prior to creating a window.
133///
134/// The returned extensions will include all extension dependencies.
135pub fn enumerate_required_extensions(
136    display_handle: RawDisplayHandle,
137) -> VkResult<&'static [*const c_char]> {
138    let extensions = match display_handle {
139        RawDisplayHandle::Windows(_) => {
140            const WINDOWS_EXTS: [*const c_char; 2] =
141                [surface::NAME.as_ptr(), win32_surface::NAME.as_ptr()];
142            &WINDOWS_EXTS
143        }
144
145        RawDisplayHandle::Wayland(_) => {
146            const WAYLAND_EXTS: [*const c_char; 2] =
147                [surface::NAME.as_ptr(), wayland_surface::NAME.as_ptr()];
148            &WAYLAND_EXTS
149        }
150
151        RawDisplayHandle::Xlib(_) => {
152            const XLIB_EXTS: [*const c_char; 2] =
153                [surface::NAME.as_ptr(), xlib_surface::NAME.as_ptr()];
154            &XLIB_EXTS
155        }
156
157        RawDisplayHandle::Xcb(_) => {
158            const XCB_EXTS: [*const c_char; 2] =
159                [surface::NAME.as_ptr(), xcb_surface::NAME.as_ptr()];
160            &XCB_EXTS
161        }
162
163        RawDisplayHandle::Android(_) => {
164            const ANDROID_EXTS: [*const c_char; 2] =
165                [surface::NAME.as_ptr(), android_surface::NAME.as_ptr()];
166            &ANDROID_EXTS
167        }
168
169        RawDisplayHandle::AppKit(_) | RawDisplayHandle::UiKit(_) => {
170            const METAL_EXTS: [*const c_char; 2] =
171                [surface::NAME.as_ptr(), metal_surface::NAME.as_ptr()];
172            &METAL_EXTS
173        }
174
175        _ => return Err(vk::Result::ERROR_EXTENSION_NOT_PRESENT),
176    };
177
178    Ok(extensions)
179}