vk_profiles_rs/
lib.rs

1//! # Vulkan Profiles Library
2//! <https://github.com/KhronosGroup/Vulkan-Profiles>
3//!
4//! ## Examples
5//! ```no_run
6//! use ash::vk;
7//! use vk_profiles_rs::vp;
8//!
9//! # fn main() -> ash::prelude::VkResult<()> {
10//! // Load the function pointers
11//! let vk_profiles = vk_profiles_rs::VulkanProfiles::linked();
12//!
13//! // Select the lunarg desktop portability 2021 profile and test instance support
14//! let profile = vp::LunargDesktopPortability2021::profile_properties();
15//! assert!(unsafe { vk_profiles.get_instance_profile_support(None, &profile)? });
16//!
17//! let instance_info = vk::InstanceCreateInfo::builder();
18//!
19//! let vp_instance_info = vp::InstanceCreateInfo::builder()
20//!     .create_info(&instance_info)
21//!     .profile(&profile);
22//!
23//! let entry = ash::Entry::linked();
24//!
25//! // The created instance is a standard [ash::Instance]
26//! let instance = unsafe { vk_profiles.create_instance(&entry, &vp_instance_info, None)? };
27//! # Ok(())
28//! # }
29//! ```
30//!
31//! ## Ash design patterns
32//!
33//! This crate uses [ash](https://github.com/ash-rs/ash) design patterns wherever possible to allow for seamless usage. Structs
34//! have builder versions, enums use the same constructs etc.
35//!
36//! ## Important notes
37//!
38//! Currently only static linking is supported. This means that the vulkan loader must also be statically linked in ash.
39
40extern crate link_cplusplus;
41
42#[cfg(feature = "debug")]
43#[doc(hidden)]
44pub mod enum_debugs;
45mod prelude;
46pub mod vp;
47
48use ash::prelude::VkResult;
49use ash::vk;
50use prelude::*;
51use std::ffi::c_void;
52use vp::*;
53
54/// A wrapper struct that provides access to the vulkan profiles functions.
55#[derive(Clone)]
56pub struct VulkanProfiles {
57    profiles_fn: vp::ProfilesFn,
58}
59
60impl VulkanProfiles {
61    /// Loads the function pointers when the vulkan profiles library is statically 
62    /// linked (which is currently the only option).
63    pub fn linked() -> Self {
64        VulkanProfiles {
65            profiles_fn: vp::ProfilesFn::load_static(),
66        }
67    }
68
69    /// Returns the raw function pointer table
70    pub fn profiles_fn(&self) -> &vp::ProfilesFn {
71        &self.profiles_fn
72    }
73
74    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profiles>
75    pub unsafe fn get_profiles(&self) -> VkResult<Vec<ProfileProperties>> {
76        read_into_uninitialized_vector(|count, data| (self.profiles_fn.get_profiles)(count, data))
77    }
78
79    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-fallbacks>
80    pub unsafe fn get_profile_fallbacks(
81        &self,
82        profile: &ProfileProperties,
83    ) -> VkResult<Vec<ProfileProperties>> {
84        read_into_uninitialized_vector(|count, data| {
85            (self.profiles_fn.get_profile_fallbacks)(profile, count, data)
86        })
87    }
88
89    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-check-instance-level-support>
90    pub unsafe fn get_instance_profile_support(
91        &self,
92        layer: Option<&::std::ffi::CStr>,
93        profile: &ProfileProperties,
94    ) -> VkResult<bool> {
95        let layer = match layer {
96            Some(layer) => layer.as_ptr(),
97            _ => std::ptr::null(),
98        };
99
100        let mut supported: vk::Bool32 = 0;
101        (self.profiles_fn.get_instance_profile_support)(layer, profile, &mut supported).result()?;
102        if supported == 0 {
103            Ok(false)
104        } else {
105            Ok(true)
106        }
107    }
108
109    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-create-instance-with-profile>
110    pub unsafe fn create_instance(
111        &self,
112        entry: &ash::Entry,
113        create_info: &InstanceCreateInfo,
114        allocator: Option<vk::AllocationCallbacks>,
115    ) -> VkResult<ash::Instance> {
116        let allocator = match allocator {
117            Some(allocator) => &allocator,
118            _ => std::ptr::null(),
119        };
120
121        let mut instance = std::mem::zeroed();
122        (self.profiles_fn.create_instance)(create_info, allocator, &mut instance).result()?;
123        Ok(ash::Instance::load(entry.static_fn(), instance))
124    }
125
126    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-check-device-level-support>
127    pub unsafe fn get_physical_device_profile_support(
128        &self,
129        instance: &ash::Instance,
130        physical_device: vk::PhysicalDevice,
131        profile: &ProfileProperties,
132    ) -> VkResult<bool> {
133        let mut supported: vk::Bool32 = 0;
134        (self.profiles_fn.get_physical_device_profile_support)(
135            instance.handle(),
136            physical_device,
137            profile,
138            &mut supported,
139        )
140        .result()?;
141        if supported == 0 {
142            Ok(false)
143        } else {
144            Ok(true)
145        }
146    }
147
148    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-create-device-with-profile>
149    pub unsafe fn create_device(
150        &self,
151        instance: &ash::Instance,
152        physical_device: vk::PhysicalDevice,
153        create_info: &DeviceCreateInfo,
154        allocator: Option<vk::AllocationCallbacks>,
155    ) -> VkResult<ash::Device> {
156        let allocator = match allocator {
157            Some(allocator) => &allocator,
158            _ => std::ptr::null(),
159        };
160
161        let mut device = std::mem::zeroed();
162        (self.profiles_fn.create_device)(physical_device, create_info, allocator, &mut device)
163            .result()?;
164        Ok(ash::Device::load(instance.fp_v1_0(), device))
165    }
166
167    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-instance-extensions>
168    pub unsafe fn get_profile_instance_extension_properties(
169        &self,
170        profile: &ProfileProperties,
171    ) -> VkResult<Vec<vk::ExtensionProperties>> {
172        read_into_uninitialized_vector(|count, data| {
173            (self.profiles_fn.get_profile_instance_extension_properties)(profile, count, data)
174        })
175    }
176
177    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-device-extensions>
178    pub unsafe fn get_profile_device_extension_properties(
179        &self,
180        profile: &ProfileProperties,
181    ) -> VkResult<Vec<vk::ExtensionProperties>> {
182        read_into_uninitialized_vector(|count, data| {
183            (self.profiles_fn.get_profile_device_extension_properties)(profile, count, data)
184        })
185    }
186
187    /// Due to how ash's marker traits work the passed features *must* be wrapped in a [`vk::PhysicalDeviceFeatures2`] struct.
188    /// 
189    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-features>
190    pub unsafe fn get_profile_features(
191        &self,
192        profile: &ProfileProperties,
193        features: &mut vk::PhysicalDeviceFeatures2,
194    ) {
195        (self.profiles_fn.get_profile_features)(profile, features as *mut _ as *mut c_void);
196    }
197
198    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-features>
199    pub unsafe fn get_profile_feature_structure_types(
200        &self,
201        profile: &ProfileProperties,
202    ) -> VkResult<Vec<vk::StructureType>> {
203        read_into_uninitialized_vector(|count, data| {
204            (self.profiles_fn.get_profile_feature_structure_types)(profile, count, data)
205        })
206    }
207
208    /// Due to how ash's marker traits work the passed properties *must* be wrapped in a [`vk::PhysicalDeviceProperties2`] struct.
209    /// 
210    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-device-properties>
211    pub unsafe fn get_profile_properties(
212        &self,
213        profile: &ProfileProperties,
214        properties: &mut vk::PhysicalDeviceProperties2,
215    ) {
216        (self.profiles_fn.get_profile_properties)(profile, properties as *mut _ as *mut c_void);
217    }
218
219    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-device-properties>
220    pub unsafe fn get_profile_property_structure_types(
221        &self,
222        profile: &ProfileProperties,
223    ) -> VkResult<Vec<vk::StructureType>> {
224        read_into_uninitialized_vector(|count, data| {
225            (self.profiles_fn.get_profile_property_structure_types)(profile, count, data)
226        })
227    }
228
229    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-queue-family-properties>
230    pub unsafe fn get_profile_queue_family_properties(
231        &self,
232        profile: &ProfileProperties,
233        properties: &mut [vk::QueueFamilyProperties2],
234    ) -> VkResult<()> {
235        let mut count = properties.len() as u32;
236        (self.profiles_fn.get_profile_queue_family_properties)(
237            profile,
238            &mut count,
239            properties.as_mut_ptr(),
240        )
241        .result()?;
242        assert_eq!(count as usize, properties.len());
243        Ok(())
244    }
245
246    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-queue-family-properties>
247    pub unsafe fn get_profile_queue_family_structure_types(
248        &self,
249        profile: &ProfileProperties,
250    ) -> VkResult<Vec<vk::StructureType>> {
251        read_into_uninitialized_vector(|count, data| {
252            (self.profiles_fn.get_profile_queue_family_structure_types)(profile, count, data)
253        })
254    }
255
256    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-format-properties>
257    pub unsafe fn get_profile_formats(
258        &self,
259        profile: &ProfileProperties,
260    ) -> VkResult<Vec<vk::Format>> {
261        read_into_uninitialized_vector(|count, data| {
262            (self.profiles_fn.get_profile_formats)(profile, count, data)
263        })
264    }
265
266    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-format-properties>
267    pub unsafe fn get_profile_format_properties(
268        &self,
269        profile: &ProfileProperties,
270        format: vk::Format,
271        p_next: &mut vk::BaseOutStructure,
272    ) {
273        (self.profiles_fn.get_profile_format_properties)(
274            profile,
275            format,
276            p_next as *mut _ as *mut c_void,
277        );
278    }
279
280    /// See <https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/profiles_api_library.html#user-content-query-profile-format-properties>
281    pub unsafe fn get_profile_format_structure_types(
282        &self,
283        profile: &ProfileProperties,
284    ) -> VkResult<Vec<vk::StructureType>> {
285        read_into_uninitialized_vector(|count, data| {
286            (self.profiles_fn.get_profile_format_structure_types)(profile, count, data)
287        })
288    }
289}
290
291#[cfg(test)]
292mod tests {
293    use crate::vp;
294    use crate::VulkanProfiles;
295    use ash::vk;
296
297    fn create_instance(profiles: &VulkanProfiles) -> (vp::ProfileProperties, ash::Instance) {
298        let profile = vp::LunargDesktopPortability2021::profile_properties();
299        assert!(unsafe {
300            profiles
301                .get_instance_profile_support(None, &profile)
302                .unwrap()
303        });
304
305        let entry = ash::Entry::linked();
306
307        let instance_info = vk::InstanceCreateInfo::builder();
308        let vp_instance_info = vp::InstanceCreateInfo::builder()
309            .create_info(&instance_info)
310            .profile(&profile);
311
312        let instance = unsafe {
313            profiles
314                .create_instance(&entry, &vp_instance_info, None)
315                .unwrap()
316        };
317
318        (profile, instance)
319    }
320
321    #[test]
322    fn test_enumerate_profiles() {
323        let vk_profiles = VulkanProfiles::linked();
324
325        let profiles = unsafe { vk_profiles.get_profiles().unwrap() };
326
327        assert!(profiles.len() > 0);
328        for profile in &profiles {
329            println!(
330                "Profile {:?}: {:?}",
331                unsafe {
332                    vk_profiles
333                        .get_instance_profile_support(None, profile)
334                        .unwrap()
335                },
336                profile
337            );
338        }
339
340        unsafe { vk_profiles.get_profile_fallbacks(&profiles[0]).unwrap() };
341    }
342
343    #[test]
344    fn test_enumerate_profile_details() {
345        let vk_profiles = VulkanProfiles::linked();
346
347        let profile = unsafe { vk_profiles.get_profiles().unwrap() }[0];
348
349        unsafe {
350            vk_profiles
351                .get_profile_instance_extension_properties(&profile)
352                .unwrap()
353        };
354        unsafe {
355            vk_profiles
356                .get_profile_device_extension_properties(&profile)
357                .unwrap()
358        };
359        unsafe {
360            vk_profiles
361                .get_profile_feature_structure_types(&profile)
362                .unwrap()
363        };
364        unsafe {
365            vk_profiles
366                .get_profile_property_structure_types(&profile)
367                .unwrap()
368        };
369        unsafe {
370            vk_profiles
371                .get_profile_queue_family_structure_types(&profile)
372                .unwrap()
373        };
374        unsafe { vk_profiles.get_profile_formats(&profile).unwrap() };
375        unsafe {
376            vk_profiles
377                .get_profile_property_structure_types(&profile)
378                .unwrap()
379        };
380    }
381
382    #[test]
383    fn test_create_instance() {
384        let (_, instance) = create_instance(&VulkanProfiles::linked());
385
386        unsafe { instance.destroy_instance(None) };
387    }
388
389    #[test]
390    fn test_create_device() {
391        let vk_profiles = VulkanProfiles::linked();
392
393        let (profile, instance) = create_instance(&vk_profiles);
394
395        let physical_device = unsafe { instance.enumerate_physical_devices().unwrap() }
396            .into_iter()
397            .find(|device| {
398                let props = unsafe { instance.get_physical_device_properties(*device) };
399                println!("PhysicalDevice: {:?}", unsafe {
400                    std::ffi::CStr::from_ptr(props.device_name.as_ptr())
401                });
402                unsafe {
403                    vk_profiles
404                        .get_physical_device_profile_support(&instance, *device, &profile)
405                        .expect("Error queueing physical device support")
406                }
407            })
408            .expect("Failed to find suitable physical device");
409
410        let queue_info = vk::DeviceQueueCreateInfo::builder()
411            .queue_family_index(0)
412            .queue_priorities(&[1.0]);
413
414        let device_info =
415            vk::DeviceCreateInfo::builder().queue_create_infos(std::slice::from_ref(&queue_info));
416
417        let vp_device_info = vp::DeviceCreateInfo::builder()
418            .create_info(&device_info)
419            .profile(&profile);
420
421        let device = unsafe {
422            vk_profiles
423                .create_device(&instance, physical_device, &vp_device_info, None)
424                .expect("Failed to create device")
425        };
426
427        unsafe { device.destroy_device(None) };
428
429        unsafe { instance.destroy_instance(None) };
430
431        println!("{:?}", vk::ImageUsageFlags::COLOR_ATTACHMENT);
432    }
433}