vulk_rs/
lib.rs

1//! # Opinionated low-level Rust bindings for Vulkan
2//! Bindgen used to generate the native unsafe bindings.
3//! 
4//! Provides an opinionated OOP wrapper around the Vulkan API.
5//! 
6//! Currently heavily *work in progress*.
7//! 
8//! Relies on the `VK_LAYER_KHRONOS_validation` layer and `VK_EXT_debug_utils` extension in debug mode, however they are stripped out in release mode.
9
10#[allow(unused)]
11
12mod native;
13pub mod vk {
14    pub use native::VkPhysicalDeviceProperties as PhysicalDeviceProperties;
15    pub use native::VkQueueFamilyProperties as QueueFamilyProperties;
16    pub use native::VkPhysicalDeviceFeatures as PhysicalDeviceFeatures;
17
18    use crate::*;
19
20    pub struct Instance {
21        __instance: native::VkInstance,
22        __validation: native::VkDebugUtilsMessengerEXT,
23    }
24
25    impl Drop for Instance {
26        /// Calls `vkDestroyInstance` on the Vulkan instance.
27        fn drop(&mut self) {
28            unsafe {
29                if cfg!(debug_assertions) {
30                    assert!(!self.__validation.is_null());
31
32                    let vk_destroy_debug_utils_messenger_ext:
33                        unsafe extern "system" fn(
34                            native::VkInstance,
35                            native::VkDebugUtilsMessengerEXT,
36                            *const ::std::ffi::c_void)
37                        = std::mem::transmute(native::vkGetInstanceProcAddr
38                            (self.__instance,
39                    std::ffi::CString::new("vkDestroyDebugUtilsMessengerEXT")
40                                .unwrap()
41                                .to_owned()
42                                .as_ptr()));
43
44                    vk_destroy_debug_utils_messenger_ext(self.__instance, self.__validation, std::ptr::null());
45                }
46                native::vkDestroyInstance(self.__instance, std::ptr::null());
47            }
48        }
49    }
50
51
52    /// A Vulkan physical device.
53    /// Maps the `VkPhysicalDevice` struct.
54    /// Represents a device that hasn't been initialized yet.
55    pub struct PhysicalDevice {
56        __physical_device: native::VkPhysicalDevice,
57    }
58
59
60    pub trait InstanceMethods {
61        /// Enumerate the physical devices available to the instance.
62        /// Maps the `vkEnumeratePhysicalDevices` function.
63        fn enumerate_physical_devices(&self) -> Vec<PhysicalDevice>;
64    }
65
66    impl InstanceMethods for Instance {
67        fn enumerate_physical_devices(&self) -> Vec<PhysicalDevice> {
68            unsafe {
69                let mut num_devices: u32 = 0;
70                native::vkEnumeratePhysicalDevices(self.__instance, &mut num_devices, std::ptr::null_mut());
71                assert!(num_devices > 0);
72
73                let mut physical_devices: Vec<native::VkPhysicalDevice> = Vec::with_capacity(num_devices as usize);
74                native::vkEnumeratePhysicalDevices(self.__instance, &mut num_devices, physical_devices.as_mut_ptr());
75                physical_devices.set_len(num_devices as usize);
76
77                let mut devices: Vec<PhysicalDevice> = Vec::with_capacity(num_devices as usize);
78
79                for i in 0..num_devices {
80                    dbg!(physical_devices[i as usize]);
81                    let device = PhysicalDevice { __physical_device: physical_devices[i as usize] };
82                    assert!(!device.__physical_device.is_null());
83                    devices.push(device);
84                }
85
86                return devices;
87            }
88        }
89    }
90
91    pub trait PhysicalDeviceMethods {
92        /// Get the properties of the physical device
93        /// 
94        /// Maps the `vkGetPhysicalDeviceProperties` function
95        fn get_properties(&self) -> native::VkPhysicalDeviceProperties;
96        /// Get the queue family properties of the physical device
97        /// 
98        /// Maps the `vkGetPhysicalDeviceQueueFamilyProperties` function
99        fn get_queue_family_properties(&self) -> Vec<native::VkQueueFamilyProperties>;
100        /// Get the features of the physical device
101        /// 
102        /// Maps the `vkGetPhysicalDeviceFeatures` function
103        fn get_features(&self) -> native::VkPhysicalDeviceFeatures;
104    }
105
106    impl PhysicalDeviceMethods for PhysicalDevice {
107        fn get_properties(&self) -> native::VkPhysicalDeviceProperties {
108            unsafe {
109                let mut properties: native::VkPhysicalDeviceProperties = std::mem::zeroed();
110                native::vkGetPhysicalDeviceProperties(self.__physical_device, &mut properties);
111                return properties;
112            }
113        }
114        fn get_queue_family_properties(&self) -> Vec<native::VkQueueFamilyProperties> {
115            unsafe {
116                let mut num_queue_families: u32 = 0;
117                native::vkGetPhysicalDeviceQueueFamilyProperties(self.__physical_device, &mut num_queue_families, std::ptr::null_mut());
118                assert!(num_queue_families > 0);
119
120                let mut queue_families: Vec<native::VkQueueFamilyProperties> = Vec::with_capacity(num_queue_families as usize);
121                native::vkGetPhysicalDeviceQueueFamilyProperties(self.__physical_device, &mut num_queue_families, queue_families.as_mut_ptr());
122                queue_families.set_len(num_queue_families as usize);
123
124                return queue_families;
125            }
126        }
127        fn get_features(&self) -> native::VkPhysicalDeviceFeatures {
128            unsafe {
129                let mut features: native::VkPhysicalDeviceFeatures = std::mem::zeroed();
130                native::vkGetPhysicalDeviceFeatures(self.__physical_device, &mut features);
131                return features;
132            }
133        }
134    }
135
136    /// Create a Vulkan version number.
137    /// Similar to the `VK_MAKE_VERSION` macro from C Vulkan headers.
138    pub fn make_version(major: u32, minor: u32, patch: u32) -> u32 {
139        return (patch<<0) | (minor<<12) | (major<<22) | (0<<29);
140    }
141
142    #[cfg(debug_assertions)]
143    extern "C" fn debug_callback(
144        _message_severity: native::VkDebugUtilsMessageSeverityFlagBitsEXT,
145        _message_types: native::VkDebugUtilsMessageTypeFlagsEXT,
146        _callback_data: *const native::VkDebugUtilsMessengerCallbackDataEXT,
147        _user_data: *mut ::std::os::raw::c_void,
148    ) -> native::VkBool32 {
149        unsafe {
150            let message = std::ffi::CStr::from_ptr((*_callback_data).pMessage);
151            if (_message_severity & 
152                (native::VkDebugUtilsMessageSeverityFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
153                |native::VkDebugUtilsMessageSeverityFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT))
154                != 0 {
155                panic!("Failed validating, message from layer: {:?}", message);
156            }
157            println!("{}", format!("Validation layer debug: {}", message.to_str().unwrap()));
158        }
159        return native::VK_TRUE;
160    }
161
162    #[cfg(debug_assertions)]
163    fn setup_validation_layer(instance: native::VkInstance) -> native::VkDebugUtilsMessengerEXT {
164        let debug_utils_create_info = native::VkDebugUtilsMessengerCreateInfoEXT {
165            sType: native::VkStructureType_VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
166            pNext: std::ptr::null(),
167            flags: 0,
168            messageSeverity: 
169                native::VkDebugUtilsMessageSeverityFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
170                native::VkDebugUtilsMessageSeverityFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
171                native::VkDebugUtilsMessageSeverityFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
172                native::VkDebugUtilsMessageSeverityFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
173            messageType: 
174                native::VkDebugUtilsMessageTypeFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
175                native::VkDebugUtilsMessageTypeFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
176                native::VkDebugUtilsMessageTypeFlagBitsEXT_VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
177            pfnUserCallback: Some(debug_callback),
178            pUserData: std::ptr::null_mut(),
179        };
180        unsafe {
181            let vk_create_debug_utils_messenger_ext:
182                unsafe extern "system" fn(
183                    native::VkInstance,
184                    *const native::VkDebugUtilsMessengerCreateInfoEXT, 
185                    *const ::std::ffi::c_void, 
186                    *mut native::VkDebugUtilsMessengerEXT)
187                -> native::VkResult
188                = std::mem::transmute(native::vkGetInstanceProcAddr
189                    (instance,
190            std::ffi::CString::new("vkCreateDebugUtilsMessengerEXT")
191                        .unwrap()
192                        .to_owned()
193                        .as_ptr()));
194            let mut out: native::VkDebugUtilsMessengerEXT = std::mem::zeroed();
195            vk_create_debug_utils_messenger_ext(instance, &debug_utils_create_info, std::ptr::null(), &mut out);
196            return out;
197        }
198    }
199
200
201    /// Create a Vulkan instance.
202    /// In debug mode, the Vulkan instance will have the validation layer enabled.
203    /// In release mode, the Vulkan instance will not have the validation layer enabled.
204    /// The instance is automatically destroyed when it goes out of scope.
205    /// The instance is asserted to be valid with an `assert!(!instance.is_null())` call.
206    /// Will panic if the instance creation fails.
207    /// Maps the `vkCreateInstance` function.
208    pub fn create_instance() -> Instance {
209        let enabled_layers: Vec<&str> =
210            vec!["VK_LAYER_KHRONOS_validation\0"];
211        let layer_count = enabled_layers.len();
212        let enabled_layers: *const *const i8 = Box::into_raw(enabled_layers.into_boxed_slice()).cast_const() as *const *const i8;
213
214        let enabled_exts: Vec<&str> =
215            vec!["VK_EXT_debug_utils\0"];
216        let ext_count = enabled_exts.len();
217        let enabled_exts: *const *const i8 = Box::into_raw(enabled_exts.into_boxed_slice()).cast_const() as *const *const i8;
218
219        let application_info = native::VkApplicationInfo {
220            sType: native::VkStructureType_VK_STRUCTURE_TYPE_APPLICATION_INFO,
221            pNext: std::ptr::null(),
222            pApplicationName: c"vulk".as_ptr(),
223            applicationVersion: make_version(0, 1, 0),
224            pEngineName: c"vulk".as_ptr(),
225            engineVersion: make_version(0, 1, 0),
226            apiVersion: make_version(1, 3, 0),
227        };
228        let instance_info = native::VkInstanceCreateInfo {
229            sType: native::VkStructureType_VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
230            pNext: std::ptr::null(),
231            flags: 0,
232            pApplicationInfo: &application_info,
233            enabledLayerCount: if cfg!(debug_assertions) { layer_count as u32 } else { 0 },
234            ppEnabledLayerNames: if cfg!(debug_assertions) { enabled_layers } else { std::ptr::null() },
235            enabledExtensionCount: if cfg!(debug_assertions) { ext_count as u32 } else { 0 },
236            ppEnabledExtensionNames: if cfg!(debug_assertions) { enabled_exts } else { std::ptr::null() },
237        };
238
239        unsafe {
240            let mut instance: native::VkInstance = { std::mem::zeroed() };
241            native::vkCreateInstance(&instance_info, std::ptr::null(), &mut instance);
242            assert!(!instance.is_null());
243            #[cfg(debug_assertions)] {
244                let validation = setup_validation_layer(instance);
245                return Instance { __instance: instance, __validation: validation};
246            }
247            #[cfg(not(debug_assertions))]
248            {
249                return Instance { __instance: instance, __validation: std::ptr::null_mut()};
250            }
251        }
252    }
253
254}