Skip to main content

ferroui_vulkan/unmanaged_interop/
vulkan_instance_api.rs

1use super::vulkan_global_api::{proc_loader, read_into_vec};
2use crate::IVulkanInstance;
3use ash::vk;
4use std::ffi::CStr;
5use std::ptr;
6use std::sync::Arc;
7
8/// The entry points of Vulkan that are found through an instance.
9///
10/// The handles given to a member have to be handles of the instance the
11/// table was made for (or of its physical devices and devices), which is
12/// what makes the calls sound; the members take typed handles, and the
13/// objects of this crate pass none but those they received from the same
14/// instance.
15pub struct VulkanInstanceApi {
16    instance: Arc<dyn IVulkanInstance>,
17    fp: ash::InstanceFnV1_0,
18    fp_1_1: ash::InstanceFnV1_1,
19    /// `vkDestroyDevice` and `vkGetDeviceQueue`, which the reference asks
20    /// the instance for.
21    device_fp: ash::DeviceFnV1_0,
22    surface: ash::khr::surface::InstanceFn,
23    debug_utils: ash::ext::debug_utils::InstanceFn,
24}
25
26impl VulkanInstanceApi {
27    /// Resolves the entry points of `instance`. One the instance does not
28    /// have (the surface functions without `VK_KHR_surface`, for instance)
29    /// is replaced by a function that stops the program when it is called.
30    pub fn new(instance: Arc<dyn IVulkanInstance>) -> Self {
31        let handle = instance.handle();
32        let lookup = |name: &str| instance.get_instance_proc_address(handle, name);
33        let fp = ash::InstanceFnV1_0::load(proc_loader(lookup));
34        let fp_1_1 = ash::InstanceFnV1_1::load(proc_loader(lookup));
35        let device_fp = ash::DeviceFnV1_0::load(proc_loader(lookup));
36        let surface = ash::khr::surface::InstanceFn::load(proc_loader(lookup));
37        let debug_utils = ash::ext::debug_utils::InstanceFn::load(proc_loader(lookup));
38        Self { instance, fp, fp_1_1, device_fp, surface, debug_utils }
39    }
40
41    /// The instance of the table.
42    pub fn instance(&self) -> &Arc<dyn IVulkanInstance> {
43        &self.instance
44    }
45
46    /// `vkCreateDebugUtilsMessengerEXT`.
47    pub fn create_debug_utils_messenger_ext(
48        &self,
49        instance: vk::Instance,
50        create_info: &vk::DebugUtilsMessengerCreateInfoEXT<'_>,
51    ) -> Result<vk::DebugUtilsMessengerEXT, vk::Result> {
52        let mut messenger = vk::DebugUtilsMessengerEXT::null();
53        // SAFETY: the structure outlives the call and the result is written
54        // to a local.
55        let result = unsafe {
56            (self.debug_utils.create_debug_utils_messenger_ext)(instance, create_info, ptr::null(), &mut messenger)
57        };
58        match result {
59            vk::Result::SUCCESS => Ok(messenger),
60            error => Err(error),
61        }
62    }
63
64    /// `vkEnumeratePhysicalDevices`.
65    pub fn enumerate_physical_devices(&self, instance: vk::Instance) -> Result<Vec<vk::PhysicalDevice>, vk::Result> {
66        // SAFETY: the function writes at most `count` handles into the
67        // buffer `read_into_vec` gives it.
68        read_into_vec(|count, data| unsafe { (self.fp.enumerate_physical_devices)(instance, count, data) })
69    }
70
71    /// `vkGetPhysicalDeviceProperties`.
72    pub fn get_physical_device_properties(&self, physical_device: vk::PhysicalDevice) -> vk::PhysicalDeviceProperties {
73        let mut properties = vk::PhysicalDeviceProperties::default();
74        // SAFETY: the result is written to a local.
75        unsafe { (self.fp.get_physical_device_properties)(physical_device, &mut properties) };
76        properties
77    }
78
79    /// `vkEnumerateDeviceExtensionProperties` without a layer.
80    pub fn enumerate_device_extension_properties(
81        &self,
82        physical_device: vk::PhysicalDevice,
83    ) -> Result<Vec<vk::ExtensionProperties>, vk::Result> {
84        // SAFETY: as for the physical devices.
85        read_into_vec(|count, data| unsafe {
86            (self.fp.enumerate_device_extension_properties)(physical_device, ptr::null(), count, data)
87        })
88    }
89
90    /// `vkGetPhysicalDeviceSurfaceSupportKHR`: whether the queue family can
91    /// present to the surface.
92    pub fn get_physical_device_surface_support_khr(
93        &self,
94        physical_device: vk::PhysicalDevice,
95        queue_family_index: u32,
96        surface: vk::SurfaceKHR,
97    ) -> Result<bool, vk::Result> {
98        let mut supported = vk::FALSE;
99        // SAFETY: the result is written to a local.
100        let result = unsafe {
101            (self.surface.get_physical_device_surface_support_khr)(
102                physical_device,
103                queue_family_index,
104                surface,
105                &mut supported,
106            )
107        };
108        match result {
109            vk::Result::SUCCESS => Ok(supported != vk::FALSE),
110            error => Err(error),
111        }
112    }
113
114    /// `vkGetPhysicalDeviceQueueFamilyProperties`.
115    pub fn get_physical_device_queue_family_properties(
116        &self,
117        physical_device: vk::PhysicalDevice,
118    ) -> Vec<vk::QueueFamilyProperties> {
119        // SAFETY: as for the physical devices; the function has no result.
120        read_into_vec(|count, data| unsafe {
121            (self.fp.get_physical_device_queue_family_properties)(physical_device, count, data);
122            vk::Result::SUCCESS
123        })
124        .unwrap_or_default()
125    }
126
127    /// `vkCreateDevice`.
128    pub fn create_device(
129        &self,
130        physical_device: vk::PhysicalDevice,
131        create_info: &vk::DeviceCreateInfo<'_>,
132    ) -> Result<vk::Device, vk::Result> {
133        let mut device = vk::Device::null();
134        // SAFETY: the lifetime of the structure covers what it points to,
135        // and the result is written to a local.
136        let result = unsafe { (self.fp.create_device)(physical_device, create_info, ptr::null(), &mut device) };
137        match result {
138            vk::Result::SUCCESS => Ok(device),
139            error => Err(error),
140        }
141    }
142
143    /// `vkDestroyDevice`. The device and its objects must not be used
144    /// afterwards.
145    pub fn destroy_device(&self, device: vk::Device) {
146        // SAFETY: the caller owns the device and gives it up.
147        unsafe { (self.device_fp.destroy_device)(device, ptr::null()) };
148    }
149
150    /// `vkGetDeviceQueue`.
151    pub fn get_device_queue(&self, device: vk::Device, queue_family_index: u32, queue_index: u32) -> vk::Queue {
152        let mut queue = vk::Queue::null();
153        // SAFETY: the result is written to a local.
154        unsafe { (self.device_fp.get_device_queue)(device, queue_family_index, queue_index, &mut queue) };
155        queue
156    }
157
158    /// `vkGetDeviceProcAddr`: the address of a device-level entry point,
159    /// zero when the device does not have it.
160    pub fn get_device_proc_addr(&self, device: vk::Device, name: &CStr) -> isize {
161        // SAFETY: the name is a zero-terminated string.
162        let address = unsafe { (self.fp.get_device_proc_addr)(device, name.as_ptr()) };
163        address.map_or(0, |address| address as usize as isize)
164    }
165
166    /// `vkDestroySurfaceKHR`. The surface must not be used afterwards.
167    pub fn destroy_surface_khr(&self, instance: vk::Instance, surface: vk::SurfaceKHR) {
168        // SAFETY: the caller owns the surface and gives it up.
169        unsafe { (self.surface.destroy_surface_khr)(instance, surface, ptr::null()) };
170    }
171
172    /// `vkGetPhysicalDeviceSurfaceFormatsKHR`.
173    pub fn get_physical_device_surface_formats_khr(
174        &self,
175        physical_device: vk::PhysicalDevice,
176        surface: vk::SurfaceKHR,
177    ) -> Result<Vec<vk::SurfaceFormatKHR>, vk::Result> {
178        // SAFETY: as for the physical devices.
179        read_into_vec(|count, data| unsafe {
180            (self.surface.get_physical_device_surface_formats_khr)(physical_device, surface, count, data)
181        })
182    }
183
184    /// `vkGetPhysicalDeviceMemoryProperties`.
185    pub fn get_physical_device_memory_properties(
186        &self,
187        physical_device: vk::PhysicalDevice,
188    ) -> vk::PhysicalDeviceMemoryProperties {
189        let mut properties = vk::PhysicalDeviceMemoryProperties::default();
190        // SAFETY: the result is written to a local.
191        unsafe { (self.fp.get_physical_device_memory_properties)(physical_device, &mut properties) };
192        properties
193    }
194
195    /// `vkGetPhysicalDeviceSurfaceCapabilitiesKHR`.
196    pub fn get_physical_device_surface_capabilities_khr(
197        &self,
198        physical_device: vk::PhysicalDevice,
199        surface: vk::SurfaceKHR,
200    ) -> Result<vk::SurfaceCapabilitiesKHR, vk::Result> {
201        let mut capabilities = vk::SurfaceCapabilitiesKHR::default();
202        // SAFETY: the result is written to a local.
203        let result = unsafe {
204            (self.surface.get_physical_device_surface_capabilities_khr)(physical_device, surface, &mut capabilities)
205        };
206        match result {
207            vk::Result::SUCCESS => Ok(capabilities),
208            error => Err(error),
209        }
210    }
211
212    /// `vkGetPhysicalDeviceSurfacePresentModesKHR`.
213    pub fn get_physical_device_surface_present_modes_khr(
214        &self,
215        physical_device: vk::PhysicalDevice,
216        surface: vk::SurfaceKHR,
217    ) -> Result<Vec<vk::PresentModeKHR>, vk::Result> {
218        // SAFETY: as for the physical devices.
219        read_into_vec(|count, data| unsafe {
220            (self.surface.get_physical_device_surface_present_modes_khr)(physical_device, surface, count, data)
221        })
222    }
223
224    /// `vkGetPhysicalDeviceProperties2`: fills the structure and the
225    /// structures chained to it.
226    pub fn get_physical_device_properties2(
227        &self,
228        physical_device: vk::PhysicalDevice,
229        properties: &mut vk::PhysicalDeviceProperties2<'_>,
230    ) {
231        // SAFETY: the lifetime of the structure covers its chain, and the
232        // function writes to the structures of the chain only.
233        unsafe { (self.fp_1_1.get_physical_device_properties2)(physical_device, properties) };
234    }
235}