1use crate::core::Instance;
3use crate::{core as vk, core::make_api_version};
4use libloading::Library;
5use std::{
6 ffi::{CStr, OsStr},
7 sync::Arc,
8};
9
10#[derive(Debug, PartialEq)]
12pub enum LoadError {
13 InvalidMetadata(&'static str),
14 LibraryOpen(String),
16 MissingSymbol(&'static str),
18 NullHandle(&'static str),
20}
21
22impl std::fmt::Display for LoadError {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 match self {
25 Self::InvalidMetadata(s) => write!(f, "invalid Vulkan import metadata: {s}"),
26 Self::LibraryOpen(s) => write!(f, "Vulkan loader: {s}"),
27 Self::MissingSymbol(s) => write!(f, "missing Vulkan command: {s}"),
28 Self::NullHandle(s) => write!(f, "null Vulkan {s} handle"),
29 }
30 }
31}
32
33impl std::error::Error for LoadError {}
34
35#[derive(Debug, PartialEq)]
37pub enum CallError {
38 EnumerationUnstable {
40 attempts: u32,
41 },
42 InitializationFailed(super::InitializationFailure),
45 Vulkan(vk::Result),
46 MissingCommand(&'static str),
47 InvalidMetadata(&'static str),
49 FeatureNotEnabled {
51 structure: vk::StructureType,
52 member: &'static str,
53 },
54 HostAllocationFailed,
55 InvalidOutput(&'static str),
56 CountOverflow(usize),
57 SliceLengthMismatch {
59 parameter: &'static str,
60 expected: usize,
61 actual: usize,
62 },
63}
64
65impl std::fmt::Display for CallError {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 match self {
68 Self::EnumerationUnstable { attempts } => write!(
69 f,
70 "Vulkan enumeration did not stabilize after {attempts} attempts"
71 ),
72 Self::InitializationFailed(failure) => failure.fmt(f),
73 Self::Vulkan(r) => write!(f, "Vulkan result {}", r.as_raw()),
74 Self::MissingCommand(n) => write!(f, "missing Vulkan command: {n}"),
75 Self::InvalidMetadata(reason) => write!(f, "invalid Vulkan metadata: {reason}"),
76 Self::FeatureNotEnabled { structure, member } => write!(
77 f,
78 "Vulkan feature {structure:?}::{member} is not recorded as enabled"
79 ),
80 Self::HostAllocationFailed => f.write_str("Vulkan host allocation failed"),
81 Self::InvalidOutput(reason) => write!(f, "invalid Vulkan output: {reason}"),
82 Self::CountOverflow(count) => write!(f, "Vulkan count exceeds u32: {count}"),
83 Self::SliceLengthMismatch {
84 parameter,
85 expected,
86 actual,
87 } => {
88 write!(f, "Vulkan {parameter} length {actual}, expected {expected}")
89 }
90 }
91 }
92}
93
94impl std::error::Error for CallError {
95 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
96 match self {
97 Self::InitializationFailed(failure) => Some(failure),
98 _ => None,
99 }
100 }
101}
102
103impl From<vk::Result> for CallError {
104 fn from(r: vk::Result) -> Self {
109 Self::Vulkan(r)
110 }
111}
112
113#[derive(Clone)]
115pub struct Entry {
116 pub(crate) library: Option<Arc<Library>>,
117 pub(crate) gipa: unsafe extern "system" fn(
118 vk::InstanceHandle,
119 *const std::ffi::c_char,
120 ) -> vk::PFN_vkVoidFunction,
121 fp: vk::FnEntry,
122}
123
124impl Entry {
125 pub unsafe fn new() -> Result<Self, LoadError> {
131 #[cfg(windows)]
132 let path = "vulkan-1.dll";
133 #[cfg(any(target_os = "macos", target_os = "ios"))]
134 let path = "libvulkan.dylib";
135 #[cfg(any(target_os = "android", target_os = "fuchsia"))]
136 let path = "libvulkan.so";
137 #[cfg(not(any(
138 windows,
139 target_os = "macos",
140 target_os = "ios",
141 target_os = "android",
142 target_os = "fuchsia"
143 )))]
144 let path = "libvulkan.so.1";
145 unsafe { Self::new_from_path(path) }
147 }
148
149 pub unsafe fn new_from_path(path: impl AsRef<OsStr>) -> Result<Self, LoadError> {
155 let library =
157 Arc::new(unsafe { Library::new(path) }.map_err(|e| LoadError::LibraryOpen(e.to_string()))?);
158 let gipa = unsafe {
160 library.get::<unsafe extern "system" fn(
161 vk::InstanceHandle,
162 *const std::ffi::c_char,
163 ) -> vk::PFN_vkVoidFunction>(b"vkGetInstanceProcAddr\0")
164 }
165 .map_err(|_| LoadError::MissingSymbol("vkGetInstanceProcAddr"))?;
166 let mut entry = unsafe { Self::new_from_resolver(*gipa) }?;
168 entry.library = Some(library);
169 Ok(entry)
170 }
171
172 pub unsafe fn new_from_resolver(
178 gipa: unsafe extern "system" fn(
179 vk::InstanceHandle,
180 *const std::ffi::c_char,
181 ) -> vk::PFN_vkVoidFunction,
182 ) -> Result<Self, LoadError> {
183 let fp = unsafe { vk::FnEntry::new_from_resolver(gipa) };
185 for (present, name) in [
186 (fp.create_instance.is_some(), "vkCreateInstance"),
187 (
188 fp.enumerate_instance_extension_properties.is_some(),
189 "vkEnumerateInstanceExtensionProperties",
190 ),
191 (
192 fp.enumerate_instance_layer_properties.is_some(),
193 "vkEnumerateInstanceLayerProperties",
194 ),
195 ] {
196 if !present {
197 return Err(LoadError::MissingSymbol(name));
198 }
199 }
200 Ok(Self {
201 library: None,
202 gipa,
203 fp,
204 })
205 }
206
207 pub fn fp(&self) -> &vk::FnEntry {
209 &self.fp
210 }
211
212 pub unsafe fn get_instance_proc_addr(
218 &self,
219 instance: vk::InstanceHandle,
220 name: &CStr,
221 ) -> vk::PFN_vkVoidFunction {
222 unsafe { (self.gipa)(instance, name.as_ptr()) }
224 }
225
226 pub unsafe fn create_instance(
232 &self,
233 create_info: &vk::InstanceCreateInfo,
234 allocator: Option<&vk::AllocationCallbacks>,
235 ) -> Result<Instance, CallError> {
236 unsafe { crate::core::create_instance(self, create_info, allocator) }
238 }
239}
240
241use crate::core::command::commands;
242commands! { Entry, entry;
243 pub fn enumerate_instance_extension_properties(
252 layer_name: Option<&std::ffi::CStr>,
253 ) -> Result<Vec<vk::ExtensionProperties>, CallError> {
254 let f = entry
255 .fp
256 .enumerate_instance_extension_properties
257 .ok_or(CallError::MissingCommand(
258 "vkEnumerateInstanceExtensionProperties",
259 ))?;
260 let layer_ptr = layer_name.map_or(std::ptr::null(), |l| l.as_ptr());
261 unsafe { super::enumerate::enumerate(|count, data| f(layer_ptr, count, data)) }
263 }
264
265 pub fn enumerate_instance_layer_properties() -> Result<Vec<vk::LayerProperties>, CallError> {
271 let f = entry
272 .fp
273 .enumerate_instance_layer_properties
274 .ok_or(CallError::MissingCommand(
275 "vkEnumerateInstanceLayerProperties",
276 ))?;
277 unsafe { super::enumerate::enumerate(|count, data| f(count, data)) }
279 }
280
281 pub fn enumerate_instance_version() -> Result<u32, vk::Result> {
283 let Some(f) = entry.fp.enumerate_instance_version else {
284 return Ok(make_api_version(0, 1, 0, 0));
285 };
286 let mut version = 0;
287 let result = unsafe { f(&mut version) };
289 if result == vk::Result::SUCCESS {
290 Ok(version)
291 } else {
292 Err(result)
293 }
294 }
295}