vulkane 0.4.5

Vulkan API bindings generated entirely from vk.xml, with a complete safe RAII wrapper covering compute and graphics: instance/device/queue, buffer, image, sampler, render pass, framebuffer, graphics + compute pipelines, swapchain, a VMA-style sub-allocator with TLSF + linear pools and defragmentation, sync primitives (fences, binary + timeline semaphores, sync2 barriers), query pools, and optional GLSL/WGSL/HLSL→SPIR-V compilation via naga or shaderc. Supports Vulkan 1.2.175 onward — swap vk.xml and rebuild.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
//! Safe wrapper for `VkSurfaceKHR` — the link between Vulkan and a
//! platform window system.
//!
//! Surfaces are platform-specific. The user creates one via the
//! constructor matching their windowing system:
//!
//! - [`Surface::from_win32`] — Win32 (Windows)
//! - [`Surface::from_wayland`] — Wayland (Linux)
//! - [`Surface::from_xlib`] — Xlib (Linux / *BSD)
//! - [`Surface::from_xcb`] — Xcb (Linux / *BSD)
//! - [`Surface::from_metal`] — Metal (macOS / iOS via MoltenVK)
//!
//! The surface itself does very little — its purpose is to be the
//! target of a [`Swapchain`](super::Swapchain), which is what actually
//! produces presentable images.
//!
//! ## Required instance extensions
//!
//! Creating any surface requires `VK_KHR_surface` to be enabled at
//! [`Instance`](super::Instance) creation time, plus the
//! platform-specific extension:
//!
//! - Win32: `VK_KHR_win32_surface`
//! - Wayland: `VK_KHR_wayland_surface`
//! - Xlib: `VK_KHR_xlib_surface`
//! - Xcb: `VK_KHR_xcb_surface`
//! - Metal: `VK_EXT_metal_surface`
//!
//! Use [`InstanceCreateInfo::enabled_extensions`](super::InstanceCreateInfo::enabled_extensions)
//! to enable them.

use super::instance::InstanceInner;
use super::physical::PhysicalDevice;
use super::{Error, Instance, Result, check};
use crate::raw::bindings::*;
use std::sync::Arc;

/// Standard names for the surface-related instance extensions.
pub const KHR_SURFACE_EXTENSION: &str = "VK_KHR_surface";
/// Required on Windows for [`Surface::from_win32`].
pub const KHR_WIN32_SURFACE_EXTENSION: &str = "VK_KHR_win32_surface";
/// Required on Wayland Linux for [`Surface::from_wayland`].
pub const KHR_WAYLAND_SURFACE_EXTENSION: &str = "VK_KHR_wayland_surface";
/// Required on Xlib Linux / *BSD for [`Surface::from_xlib`].
pub const KHR_XLIB_SURFACE_EXTENSION: &str = "VK_KHR_xlib_surface";
/// Required on Xcb Linux / *BSD for [`Surface::from_xcb`].
pub const KHR_XCB_SURFACE_EXTENSION: &str = "VK_KHR_xcb_surface";
/// Required on macOS / iOS for [`Surface::from_metal`].
pub const EXT_METAL_SURFACE_EXTENSION: &str = "VK_EXT_metal_surface";
/// Required on every device that owns a swapchain.
pub const KHR_SWAPCHAIN_EXTENSION: &str = "VK_KHR_swapchain";

/// A safe wrapper around `VkSurfaceKHR`.
///
/// Surfaces are destroyed automatically on drop. They keep the parent
/// instance alive via an `Arc`.
pub struct Surface {
    pub(crate) handle: VkSurfaceKHR,
    pub(crate) instance: Arc<InstanceInner>,
}

// Safety: VkSurfaceKHR is a non-dispatchable handle, safe to share between
// threads. Creation/destruction must be externally synchronized; we
// only do those at construction and Drop.
unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl Surface {
    /// Create a `VkSurfaceKHR` from a Win32 `(HINSTANCE, HWND)` pair.
    ///
    /// # Safety
    ///
    /// Both `hinstance` and `hwnd` must be valid Win32 handles for the
    /// lifetime of the resulting `Surface`. The handles can be obtained
    /// from any Win32 window library (`winit`, raw Win32 API, etc.).
    pub unsafe fn from_win32(
        instance: &Instance,
        hinstance: *mut std::ffi::c_void,
        hwnd: *mut std::ffi::c_void,
    ) -> Result<Self> {
        let create = instance
            .inner
            .dispatch
            .vkCreateWin32SurfaceKHR
            .ok_or(Error::MissingFunction("vkCreateWin32SurfaceKHR"))?;

        let info = VkWin32SurfaceCreateInfoKHR {
            sType: VkStructureType::STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
            hinstance,
            hwnd,
            ..Default::default()
        };

        let mut handle: VkSurfaceKHR = 0;
        // Safety: info is valid for the call; instance handle is valid;
        // the caller has guaranteed the Win32 handles are live.
        check(unsafe { create(instance.inner.handle, &info, std::ptr::null(), &mut handle) })?;

        Ok(Self {
            handle,
            instance: Arc::clone(&instance.inner),
        })
    }

    /// Create a `VkSurfaceKHR` from a Wayland `(wl_display, wl_surface)`
    /// pair.
    ///
    /// # Safety
    ///
    /// Both pointers must be valid for the lifetime of the resulting
    /// `Surface`. The pointers are reinterpreted via `as` casts to
    /// satisfy the bindings' opaque-pointer wrapping (the codegen
    /// treats Wayland's `wl_display` and `wl_surface` C types as
    /// already-pointer aliases, so the field type is `*mut *mut c_void`
    /// even though the value is just an opaque handle).
    pub unsafe fn from_wayland(
        instance: &Instance,
        display: *mut std::ffi::c_void,
        surface: *mut std::ffi::c_void,
    ) -> Result<Self> {
        let create = instance
            .inner
            .dispatch
            .vkCreateWaylandSurfaceKHR
            .ok_or(Error::MissingFunction("vkCreateWaylandSurfaceKHR"))?;

        let info = VkWaylandSurfaceCreateInfoKHR {
            sType: VkStructureType::STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
            display: display as *mut _,
            surface: surface as *mut _,
            ..Default::default()
        };

        let mut handle: VkSurfaceKHR = 0;
        // Safety: info is valid; caller has guaranteed pointer validity.
        check(unsafe { create(instance.inner.handle, &info, std::ptr::null(), &mut handle) })?;

        Ok(Self {
            handle,
            instance: Arc::clone(&instance.inner),
        })
    }

    /// Create a `VkSurfaceKHR` from an Xlib `(Display*, Window)` pair.
    ///
    /// `display` is a pointer to an `Xlib` `Display` connection
    /// (typically obtained from `XOpenDisplay`). `window` is the X11
    /// window XID. The bindings generator emits `Window` as
    /// `c_ulong`, which matches the C ABI on every platform that
    /// implements Xlib.
    ///
    /// # Safety
    ///
    /// `display` must be a valid Xlib `Display*` for the lifetime of
    /// the resulting `Surface`. `window` must be a valid X11 window
    /// XID belonging to that display.
    pub unsafe fn from_xlib(
        instance: &Instance,
        display: *mut std::ffi::c_void,
        window: std::ffi::c_ulong,
    ) -> Result<Self> {
        let create = instance
            .inner
            .dispatch
            .vkCreateXlibSurfaceKHR
            .ok_or(Error::MissingFunction("vkCreateXlibSurfaceKHR"))?;

        let info = VkXlibSurfaceCreateInfoKHR {
            sType: VkStructureType::STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
            // The bindings type the dpy field as `*mut Display` where
            // Display is itself an opaque pointer alias, so the field
            // type is `*mut *mut c_void`. Cast through the alias.
            dpy: display as *mut _,
            window,
            ..Default::default()
        };

        let mut handle: VkSurfaceKHR = 0;
        // Safety: info is valid for the call; instance handle is valid;
        // the caller has guaranteed display + window are live.
        check(unsafe { create(instance.inner.handle, &info, std::ptr::null(), &mut handle) })?;

        Ok(Self {
            handle,
            instance: Arc::clone(&instance.inner),
        })
    }

    /// Create a `VkSurfaceKHR` from an Xcb `(xcb_connection_t*, xcb_window_t)`
    /// pair.
    ///
    /// `connection` is a pointer to an `xcb_connection_t` (typically
    /// from `xcb_connect`). `window` is an `xcb_window_t` XID, which is
    /// a `uint32_t` per the XCB ABI.
    ///
    /// # Safety
    ///
    /// `connection` must be a valid `xcb_connection_t*` for the lifetime
    /// of the resulting `Surface`. `window` must be a valid window XID on
    /// that connection.
    pub unsafe fn from_xcb(
        instance: &Instance,
        connection: *mut std::ffi::c_void,
        window: u32,
    ) -> Result<Self> {
        let create = instance
            .inner
            .dispatch
            .vkCreateXcbSurfaceKHR
            .ok_or(Error::MissingFunction("vkCreateXcbSurfaceKHR"))?;

        let info = VkXcbSurfaceCreateInfoKHR {
            sType: VkStructureType::STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
            // Same alias-cast trick as Xlib.
            connection: connection as *mut _,
            window,
            ..Default::default()
        };

        let mut handle: VkSurfaceKHR = 0;
        // Safety: info is valid for the call; instance handle is valid;
        // the caller has guaranteed connection + window are live.
        check(unsafe { create(instance.inner.handle, &info, std::ptr::null(), &mut handle) })?;

        Ok(Self {
            handle,
            instance: Arc::clone(&instance.inner),
        })
    }

    /// Create a `VkSurfaceKHR` from a `CAMetalLayer*` (macOS / iOS via
    /// MoltenVK).
    ///
    /// # Safety
    ///
    /// `metal_layer` must be a valid pointer to a `CAMetalLayer` for
    /// the lifetime of the resulting `Surface`.
    pub unsafe fn from_metal(
        instance: &Instance,
        metal_layer: *const std::ffi::c_void,
    ) -> Result<Self> {
        let create = instance
            .inner
            .dispatch
            .vkCreateMetalSurfaceEXT
            .ok_or(Error::MissingFunction("vkCreateMetalSurfaceEXT"))?;

        let info = VkMetalSurfaceCreateInfoEXT {
            sType: VkStructureType::STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
            pLayer: metal_layer as *const _,
            ..Default::default()
        };

        let mut handle: VkSurfaceKHR = 0;
        // Safety: info is valid; caller has guaranteed layer validity.
        check(unsafe { create(instance.inner.handle, &info, std::ptr::null(), &mut handle) })?;

        Ok(Self {
            handle,
            instance: Arc::clone(&instance.inner),
        })
    }

    /// Returns the raw `VkSurfaceKHR` handle.
    pub fn raw(&self) -> VkSurfaceKHR {
        self.handle
    }

    /// Query whether the given physical device + queue family combination
    /// can present to this surface.
    pub fn supports_present(&self, physical: &PhysicalDevice, queue_family: u32) -> bool {
        let Some(get) = self.instance.dispatch.vkGetPhysicalDeviceSurfaceSupportKHR else {
            return false;
        };
        let mut supported: VkBool32 = 0;
        // Safety: physical handle and self.handle are both valid.
        let res = unsafe { get(physical.raw(), queue_family, self.handle, &mut supported) };
        res == VkResult::SUCCESS && supported != 0
    }

    /// Query the surface capabilities for the given physical device.
    pub fn capabilities(&self, physical: &PhysicalDevice) -> Result<SurfaceCapabilities> {
        let get = self
            .instance
            .dispatch
            .vkGetPhysicalDeviceSurfaceCapabilitiesKHR
            .ok_or(Error::MissingFunction(
                "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
            ))?;
        let mut raw: VkSurfaceCapabilitiesKHR = unsafe { std::mem::zeroed() };
        // Safety: physical handle and self.handle are both valid.
        check(unsafe { get(physical.raw(), self.handle, &mut raw) })?;
        Ok(SurfaceCapabilities { raw })
    }

    /// Enumerate the (format, color space) pairs the given physical
    /// device supports for this surface.
    pub fn formats(&self, physical: &PhysicalDevice) -> Result<Vec<SurfaceFormat>> {
        let get = self
            .instance
            .dispatch
            .vkGetPhysicalDeviceSurfaceFormatsKHR
            .ok_or(Error::MissingFunction(
                "vkGetPhysicalDeviceSurfaceFormatsKHR",
            ))?;
        let mut count: u32 = 0;
        // Safety: physical handle and self.handle are both valid.
        check(unsafe {
            get(
                physical.raw(),
                self.handle,
                &mut count,
                std::ptr::null_mut(),
            )
        })?;
        let mut raw: Vec<VkSurfaceFormatKHR> = vec![unsafe { std::mem::zeroed() }; count as usize];
        // Safety: raw has space for `count` elements.
        check(unsafe { get(physical.raw(), self.handle, &mut count, raw.as_mut_ptr()) })?;
        Ok(raw.into_iter().map(|r| SurfaceFormat { raw: r }).collect())
    }

    /// Enumerate the present modes the given physical device supports
    /// for this surface.
    pub fn present_modes(&self, physical: &PhysicalDevice) -> Result<Vec<PresentMode>> {
        let get = self
            .instance
            .dispatch
            .vkGetPhysicalDeviceSurfacePresentModesKHR
            .ok_or(Error::MissingFunction(
                "vkGetPhysicalDeviceSurfacePresentModesKHR",
            ))?;
        let mut count: u32 = 0;
        // Safety: physical handle and self.handle are both valid.
        check(unsafe {
            get(
                physical.raw(),
                self.handle,
                &mut count,
                std::ptr::null_mut(),
            )
        })?;
        let mut raw: Vec<VkPresentModeKHR> =
            vec![VkPresentModeKHR::PRESENT_MODE_FIFO_KHR; count as usize];
        // Safety: raw has space for `count` elements.
        check(unsafe { get(physical.raw(), self.handle, &mut count, raw.as_mut_ptr()) })?;
        Ok(raw.into_iter().map(PresentMode).collect())
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        if let Some(destroy) = self.instance.dispatch.vkDestroySurfaceKHR {
            // Safety: handle is valid; we are the sole owner.
            unsafe { destroy(self.instance.handle, self.handle, std::ptr::null()) };
        }
    }
}

/// Surface capability snapshot returned by [`Surface::capabilities`].
#[derive(Clone)]
pub struct SurfaceCapabilities {
    pub(crate) raw: VkSurfaceCapabilitiesKHR,
}

impl std::fmt::Debug for SurfaceCapabilities {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("SurfaceCapabilities")
            .field("min_image_count", &self.min_image_count())
            .field("max_image_count", &self.max_image_count())
            .field("current_extent", &self.current_extent())
            .field("min_image_extent", &self.min_image_extent())
            .field("max_image_extent", &self.max_image_extent())
            .field("supported_usage_flags", &self.supported_usage_flags())
            .field("supported_transforms", &self.supported_transforms())
            .field("current_transform", &self.current_transform())
            .field(
                "supported_composite_alpha",
                &self.supported_composite_alpha(),
            )
            .finish()
    }
}

impl SurfaceCapabilities {
    pub fn min_image_count(&self) -> u32 {
        self.raw.minImageCount
    }
    pub fn max_image_count(&self) -> u32 {
        self.raw.maxImageCount
    }
    pub fn current_extent(&self) -> (u32, u32) {
        (self.raw.currentExtent.width, self.raw.currentExtent.height)
    }
    pub fn min_image_extent(&self) -> (u32, u32) {
        (
            self.raw.minImageExtent.width,
            self.raw.minImageExtent.height,
        )
    }
    pub fn max_image_extent(&self) -> (u32, u32) {
        (
            self.raw.maxImageExtent.width,
            self.raw.maxImageExtent.height,
        )
    }
    pub fn supported_usage_flags(&self) -> u32 {
        self.raw.supportedUsageFlags
    }
    pub fn supported_transforms(&self) -> u32 {
        self.raw.supportedTransforms
    }
    pub fn current_transform(&self) -> u32 {
        self.raw.currentTransform
    }
    pub fn supported_composite_alpha(&self) -> u32 {
        self.raw.supportedCompositeAlpha
    }
}

/// One supported `(format, color_space)` pair returned by
/// [`Surface::formats`].
#[derive(Clone, Copy)]
pub struct SurfaceFormat {
    pub(crate) raw: VkSurfaceFormatKHR,
}

impl std::fmt::Debug for SurfaceFormat {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("SurfaceFormat")
            .field("format", &self.format())
            .field("color_space", &self.color_space())
            .finish()
    }
}

impl SurfaceFormat {
    pub fn format(&self) -> super::Format {
        super::Format(self.raw.format)
    }
    pub fn color_space(&self) -> VkColorSpaceKHR {
        self.raw.colorSpace
    }
}

/// One supported present mode returned by [`Surface::present_modes`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PresentMode(pub VkPresentModeKHR);

impl PresentMode {
    /// Vsync, double-buffered. Always supported.
    pub const FIFO: Self = Self(VkPresentModeKHR::PRESENT_MODE_FIFO_KHR);
    /// Vsync but allows tearing if the application falls behind.
    pub const FIFO_RELAXED: Self = Self(VkPresentModeKHR::PRESENT_MODE_FIFO_RELAXED_KHR);
    /// No vsync — render as fast as possible, may tear.
    pub const IMMEDIATE: Self = Self(VkPresentModeKHR::PRESENT_MODE_IMMEDIATE_KHR);
    /// Triple-buffered: latest frame replaces the queued one.
    pub const MAILBOX: Self = Self(VkPresentModeKHR::PRESENT_MODE_MAILBOX_KHR);
}