Skip to main content

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::{profiles, 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 minimum Vulkan 1.3 profile and test instance support
14//! let profile = profiles::LunargMinimumRequirements1_3::profile_properties();
15//! assert!(unsafe { vk_profiles.get_instance_profile_support(None, &profile)? });
16//!
17//! let instance_info = vk::InstanceCreateInfo::default();
18//! let profiles = [profile];
19//! let vp_instance_info = vp::InstanceCreateInfo::default()
20//!     .create_info(&instance_info)
21//!     .enabled_full_profiles(&profiles);
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 profiles;
47pub mod vp;
48
49use ash::prelude::VkResult;
50use ash::vk;
51use prelude::*;
52use std::ffi::{c_void, CStr};
53use vp::*;
54
55/// A wrapper struct that provides access to the vulkan profiles functions.
56#[derive(Clone)]
57pub struct VulkanProfiles {
58    profiles_fn: vp::ProfilesFn,
59}
60
61impl VulkanProfiles {
62    /// Loads the function pointers when the vulkan profiles library is statically
63    /// linked (which is currently the only option).
64    pub fn linked() -> Self {
65        VulkanProfiles {
66            profiles_fn: vp::ProfilesFn::load_static(),
67        }
68    }
69
70    /// Returns the raw function pointer table
71    pub fn profiles_fn(&self) -> &vp::ProfilesFn {
72        &self.profiles_fn
73    }
74
75    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profiles>
76    pub unsafe fn get_profiles(&self) -> VkResult<Vec<ProfileProperties>> {
77        read_into_uninitialized_vector(|count, data| (self.profiles_fn.get_profiles)(count, data))
78    }
79
80    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-fallbacks>
81    pub unsafe fn get_profile_fallbacks(
82        &self,
83        profile: &ProfileProperties,
84    ) -> VkResult<Vec<ProfileProperties>> {
85        read_into_uninitialized_vector(|count, data| {
86            (self.profiles_fn.get_profile_fallbacks)(profile, count, data)
87        })
88    }
89
90    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-check-instance-level-support>
91    pub unsafe fn get_instance_profile_support(
92        &self,
93        layer: Option<&CStr>,
94        profile: &ProfileProperties,
95    ) -> VkResult<bool> {
96        let layer = cstr_opt_ptr(layer);
97
98        let mut supported: vk::Bool32 = 0;
99        (self.profiles_fn.get_instance_profile_support)(layer, profile, &mut supported).result()?;
100        Ok(supported == 1)
101    }
102
103    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-create-instance-with-profile>
104    pub unsafe fn create_instance(
105        &self,
106        entry: &ash::Entry,
107        create_info: &InstanceCreateInfo,
108        allocator: Option<vk::AllocationCallbacks>,
109    ) -> VkResult<ash::Instance> {
110        let allocator = match allocator {
111            Some(allocator) => &allocator,
112            _ => std::ptr::null(),
113        };
114
115        let mut instance = std::mem::zeroed();
116        (self.profiles_fn.create_instance)(create_info, allocator, &mut instance).result()?;
117        Ok(ash::Instance::load(entry.static_fn(), instance))
118    }
119
120    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-check-device-level-support>
121    pub unsafe fn get_physical_device_profile_support(
122        &self,
123        instance: &ash::Instance,
124        physical_device: vk::PhysicalDevice,
125        profile: &ProfileProperties,
126    ) -> VkResult<bool> {
127        let mut supported: vk::Bool32 = 0;
128        (self.profiles_fn.get_physical_device_profile_support)(
129            instance.handle(),
130            physical_device,
131            profile,
132            &mut supported,
133        )
134        .result()?;
135        if supported == 0 {
136            Ok(false)
137        } else {
138            Ok(true)
139        }
140    }
141
142    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-create-device-with-profile>
143    pub unsafe fn create_device(
144        &self,
145        instance: &ash::Instance,
146        physical_device: vk::PhysicalDevice,
147        create_info: &DeviceCreateInfo,
148        allocator: Option<vk::AllocationCallbacks>,
149    ) -> VkResult<ash::Device> {
150        let allocator = match allocator {
151            Some(allocator) => &allocator,
152            _ => std::ptr::null(),
153        };
154
155        let mut device = std::mem::zeroed();
156        (self.profiles_fn.create_device)(physical_device, create_info, allocator, &mut device)
157            .result()?;
158        Ok(ash::Device::load(instance.fp_v1_0(), device))
159    }
160
161    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-instance-extensions>
162    pub unsafe fn get_profile_instance_extension_properties(
163        &self,
164        profile: &ProfileProperties,
165        block_name: Option<&CStr>,
166    ) -> VkResult<Vec<vk::ExtensionProperties>> {
167        let block_name = cstr_opt_ptr(block_name);
168        read_into_uninitialized_vector(|count, data| {
169            (self.profiles_fn.get_profile_instance_extension_properties)(
170                profile, block_name, count, data,
171            )
172        })
173    }
174
175    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-device-extensions>
176    pub unsafe fn get_profile_device_extension_properties(
177        &self,
178        profile: &ProfileProperties,
179        block_name: Option<&CStr>,
180    ) -> VkResult<Vec<vk::ExtensionProperties>> {
181        let block_name = cstr_opt_ptr(block_name);
182        read_into_uninitialized_vector(|count, data| {
183            (self.profiles_fn.get_profile_device_extension_properties)(
184                profile, block_name, count, data,
185            )
186        })
187    }
188
189    /// Due to how ash's marker traits work the passed features *must* be wrapped in a [`vk::PhysicalDeviceFeatures2`] struct.
190    ///
191    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-features>
192    pub unsafe fn get_profile_features(
193        &self,
194        profile: &ProfileProperties,
195        block_name: Option<&CStr>,
196        features: &mut vk::PhysicalDeviceFeatures2,
197    ) {
198        let block_name = cstr_opt_ptr(block_name);
199        (self.profiles_fn.get_profile_features)(
200            profile,
201            block_name,
202            features as *mut _ as *mut c_void,
203        );
204    }
205
206    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-features>
207    pub unsafe fn get_profile_feature_structure_types(
208        &self,
209        profile: &ProfileProperties,
210        block_name: Option<&CStr>,
211    ) -> VkResult<Vec<vk::StructureType>> {
212        let block_name = cstr_opt_ptr(block_name);
213        read_into_uninitialized_vector(|count, data| {
214            (self.profiles_fn.get_profile_feature_structure_types)(profile, block_name, count, data)
215        })
216    }
217
218    /// Due to how ash's marker traits work the passed properties *must* be wrapped in a [`vk::PhysicalDeviceProperties2`] struct.
219    ///
220    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-device-properties>
221    pub unsafe fn get_profile_properties(
222        &self,
223        profile: &ProfileProperties,
224        block_name: Option<&CStr>,
225        properties: &mut vk::PhysicalDeviceProperties2,
226    ) {
227        let block_name = cstr_opt_ptr(block_name);
228        (self.profiles_fn.get_profile_properties)(
229            profile,
230            block_name,
231            properties as *mut _ as *mut c_void,
232        );
233    }
234
235    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-device-properties>
236    pub unsafe fn get_profile_property_structure_types(
237        &self,
238        profile: &ProfileProperties,
239        block_name: Option<&CStr>,
240    ) -> VkResult<Vec<vk::StructureType>> {
241        let block_name = cstr_opt_ptr(block_name);
242        read_into_uninitialized_vector(|count, data| {
243            (self.profiles_fn.get_profile_property_structure_types)(
244                profile, block_name, count, data,
245            )
246        })
247    }
248
249    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-queue-family-properties>
250    pub unsafe fn get_profile_queue_family_properties(
251        &self,
252        profile: &ProfileProperties,
253        block_name: Option<&CStr>,
254        properties: &mut [vk::QueueFamilyProperties2],
255    ) -> VkResult<()> {
256        let block_name = cstr_opt_ptr(block_name);
257        let mut count = properties.len() as u32;
258        (self.profiles_fn.get_profile_queue_family_properties)(
259            profile,
260            block_name,
261            &mut count,
262            properties.as_mut_ptr(),
263        )
264        .result()?;
265        assert_eq!(count as usize, properties.len());
266        Ok(())
267    }
268
269    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-queue-family-properties>
270    pub unsafe fn get_profile_queue_family_structure_types(
271        &self,
272        profile: &ProfileProperties,
273        block_name: Option<&CStr>,
274    ) -> VkResult<Vec<vk::StructureType>> {
275        let block_name = cstr_opt_ptr(block_name);
276        read_into_uninitialized_vector(|count, data| {
277            (self.profiles_fn.get_profile_queue_family_structure_types)(
278                profile, block_name, count, data,
279            )
280        })
281    }
282
283    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-format-properties>
284    pub unsafe fn get_profile_formats(
285        &self,
286        profile: &ProfileProperties,
287        block_name: Option<&CStr>,
288    ) -> VkResult<Vec<vk::Format>> {
289        let block_name = cstr_opt_ptr(block_name);
290        read_into_uninitialized_vector(|count, data| {
291            (self.profiles_fn.get_profile_formats)(profile, block_name, count, data)
292        })
293    }
294
295    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-format-properties>
296    pub unsafe fn get_profile_format_properties(
297        &self,
298        profile: &ProfileProperties,
299        block_name: Option<&CStr>,
300        format: vk::Format,
301        p_next: &mut vk::BaseOutStructure,
302    ) {
303        let block_name = cstr_opt_ptr(block_name);
304        (self.profiles_fn.get_profile_format_properties)(
305            profile,
306            block_name,
307            format,
308            p_next as *mut _ as *mut c_void,
309        );
310    }
311
312    /// See <https://vulkan.lunarg.com/doc/view/1.4.335.0/windows/profiles_api_library.html#user-content-query-profile-format-properties>
313    pub unsafe fn get_profile_format_structure_types(
314        &self,
315        profile: &ProfileProperties,
316        block_name: Option<&CStr>,
317    ) -> VkResult<Vec<vk::StructureType>> {
318        let block_name = cstr_opt_ptr(block_name);
319        read_into_uninitialized_vector(|count, data| {
320            (self.profiles_fn.get_profile_format_structure_types)(profile, block_name, count, data)
321        })
322    }
323}
324
325#[cfg(test)]
326mod tests {
327    use crate::profiles;
328    use crate::vp;
329    use crate::VulkanProfiles;
330    use ash::vk;
331
332    fn create_instance(
333        entry: &ash::Entry,
334        vk_profiles: &VulkanProfiles,
335    ) -> ([vp::ProfileProperties; 2], ash::Instance) {
336        let profiles = [
337            profiles::KhrRoadmap2024::profile_properties(),
338            profiles::LunargMinimumRequirements1_3::profile_properties(),
339        ];
340        for profile in profiles {
341            assert!(unsafe {
342                vk_profiles
343                    .get_instance_profile_support(None, &profile)
344                    .unwrap()
345            });
346        }
347
348        let instance_info = vk::InstanceCreateInfo::default();
349        let vp_instance_info = vp::InstanceCreateInfo::default()
350            .enabled_full_profiles(&profiles)
351            .create_info(&instance_info);
352
353        let instance = unsafe {
354            vk_profiles
355                .create_instance(entry, &vp_instance_info, None)
356                .unwrap()
357        };
358
359        (profiles, instance)
360    }
361
362    #[test]
363    fn test_enumerate_profiles() {
364        let vk_profiles = VulkanProfiles::linked();
365
366        let profiles = unsafe { vk_profiles.get_profiles().unwrap() };
367
368        assert!(profiles.len() > 0);
369        for profile in &profiles {
370            println!(
371                "Profile {:?}: {:?}",
372                unsafe {
373                    vk_profiles
374                        .get_instance_profile_support(None, profile)
375                        .unwrap()
376                },
377                profile
378            );
379        }
380
381        unsafe { vk_profiles.get_profile_fallbacks(&profiles[0]).unwrap() };
382    }
383
384    #[test]
385    fn test_enumerate_profile_details() {
386        let vk_profiles = VulkanProfiles::linked();
387
388        let profiles = unsafe { vk_profiles.get_profiles().unwrap() };
389        let block_name = None;
390
391        for profile in profiles {
392            unsafe {
393                vk_profiles
394                    .get_profile_instance_extension_properties(&profile, block_name)
395                    .unwrap()
396            };
397            unsafe {
398                vk_profiles
399                    .get_profile_device_extension_properties(&profile, block_name)
400                    .unwrap()
401            };
402            unsafe {
403                vk_profiles
404                    .get_profile_feature_structure_types(&profile, block_name)
405                    .unwrap()
406            };
407            unsafe {
408                vk_profiles
409                    .get_profile_property_structure_types(&profile, block_name)
410                    .unwrap()
411            };
412            unsafe {
413                vk_profiles
414                    .get_profile_queue_family_structure_types(&profile, block_name)
415                    .unwrap()
416            };
417            unsafe {
418                vk_profiles
419                    .get_profile_formats(&profile, block_name)
420                    .unwrap()
421            };
422            unsafe {
423                vk_profiles
424                    .get_profile_property_structure_types(&profile, block_name)
425                    .unwrap()
426            };
427        }
428    }
429
430    #[test]
431    fn test_create_instance() {
432        let entry = ash::Entry::linked();
433        let (_, instance) = create_instance(&entry, &VulkanProfiles::linked());
434
435        unsafe { instance.destroy_instance(None) };
436    }
437
438    #[test]
439    fn test_create_device() {
440        let vk_profiles = VulkanProfiles::linked();
441        let entry = ash::Entry::linked();
442
443        let (profiles, instance) = create_instance(&entry, &vk_profiles);
444
445        let physical_device = unsafe { instance.enumerate_physical_devices().unwrap() }
446            .into_iter()
447            .find(|device| {
448                let props = unsafe { instance.get_physical_device_properties(*device) };
449                println!("PhysicalDevice: {:?}", unsafe {
450                    std::ffi::CStr::from_ptr(props.device_name.as_ptr())
451                });
452                let mut unsupported = false;
453                for profile in profiles {
454                    let supports_this = unsafe {
455                        vk_profiles
456                            .get_physical_device_profile_support(&instance, *device, &profile)
457                            .expect("Error queueing physical device support")
458                    };
459                    if !supports_this {
460                        unsupported = true;
461                        break;
462                    }
463                }
464                !unsupported
465            })
466            .expect("Failed to find suitable physical device");
467
468        let queue_priorities: [f32; 1] = [1.0];
469        let queue_info = vk::DeviceQueueCreateInfo {
470            queue_family_index: 0,
471            p_queue_priorities: queue_priorities.as_ptr(),
472            ..Default::default()
473        };
474
475        let device_info = vk::DeviceCreateInfo {
476            p_queue_create_infos: std::ptr::addr_of!(queue_info),
477            ..Default::default()
478        };
479
480        let vp_device_info = vp::DeviceCreateInfo::default()
481            .enabled_full_profiles(&profiles)
482            .create_info(&device_info)
483            .flags(vp::DeviceCreateFlagBits::DISABLE_ROBUST_ACCESS);
484        let device = unsafe {
485            vk_profiles
486                .create_device(&instance, physical_device, &vp_device_info, None)
487                .expect("Failed to create device")
488        };
489
490        unsafe { device.destroy_device(None) };
491
492        unsafe { instance.destroy_instance(None) };
493
494        println!("{:?}", vk::ImageUsageFlags::COLOR_ATTACHMENT);
495    }
496}