1#![allow(non_snake_case)]
4
5use crate::*;
6use derives::implements;
7
8use core::ffi::*;
9
10#[implements]
11pub trait ResolverInterface {
12 unsafe fn load_symbol_unconstrainted<T: FromPtr>(&self, name: &core::ffi::CStr) -> T;
13 unsafe fn load_function_unconstrainted<F: PFN>(&self) -> F;
14}
15
16#[implements]
17cfg_if::cfg_if! {
18 if #[cfg(feature = "CustomResolver")] {
19 static GLOBAL_RESOLVER: parking_lot::RwLock<Option<Box<dyn ResolverInterface>>> = parking_low::RwLock::new(None);
20
21 pub fn set_custom_resolver(resolver: Box<dyn ResolverInterface>) {
23 crate::vkfn::FunctionPointerTable::reset();
24 *GLOBAL_RESOLVER.write() = Some(resolver);
25 }
26
27 #[inline(always)]
29 pub fn get_resolver<'a>() -> &'a dyn ResolverInterface {
30 GLOBAL_RESOLVER.read().expect("no global resolver set")
31 }
32 } else if #[cfg(feature = "DynamicLoaded")] {
33 static GLOBAL_RESOLVER: std::sync::LazyLock<Box<Resolver>> = std::sync::LazyLock::new(|| Box::new(Resolver::new()));
34
35 #[cfg(windows)]
36 pub struct Resolver(crate::libloaderapi::OwnedLibrary);
37 #[cfg(not(windows))]
38 pub struct Resolver(crate::libdl::OwnedDylib);
39 impl Resolver {
40 fn new() -> Self {
41 #[cfg(target_os ="macos")]
42 fn libname() -> &'static core::ffi::CStr {
43 c"libvulkan.dylib"
49 }
50 #[cfg(windows)]
51 fn libname() -> &'static [u16] {
52 &[
53 b'v' as _,
54 b'u' as _,
55 b'l' as _,
56 b'k' as _,
57 b'a' as _,
58 b'n' as _,
59 b'-' as _,
60 b'1' as _,
61 b'.' as _,
62 b'd' as _,
63 b'l' as _,
64 b'l' as _,
65 0
66 ]
67 }
68 #[cfg(not(any(target_os = "macos", windows)))]
69 fn libname() -> &'static core::ffi::CStr {
70 c"libvulkan.so"
72 }
73
74 #[cfg(windows)]
75 match crate::libloaderapi::OwnedLibrary::open(libname()) {
76 Ok(x) => Resolver(x),
77 Err(e) => {
78 tracing::error!(
79 reason = ?e,
80 libpath = ?libname(),
81 "Failed to open libvulkan, bedrock could not continue"
82 );
83 std::process::abort();
84 }
85 }
86 #[cfg(not(windows))]
87 match crate::libdl::Dylib::open(libname(), crate::libdl::OpenFlags::RTLD_LAZY) {
88 Ok(x) => Resolver(x),
89 Err(e) => {
90 tracing::error!(
91 reason = ?e,
92 libpath = ?libname(),
93 "Failed to open libvulkan, bedrock could not continue"
94 );
95 std::process::abort();
96 }
97 }
98 }
99 }
100 impl ResolverInterface for Resolver {
101 unsafe fn load_symbol_unconstrainted<T: FromPtr>(&self, name: &core::ffi::CStr) -> T {
102 let p = match self.0.sym(name) {
103 Ok(x) => x.as_ptr(),
104 Err(e) => {
105 tracing::warn!(?name, reason = ?e, "could not resolve symbol");
106 core::ptr::null_mut()
107 }
108 };
109
110 unsafe { T::from_ptr(p as _) }
111 }
112
113 unsafe fn load_function_unconstrainted<F: PFN>(&self) -> F {
114 let p = match self.0.sym(F::NAME_CSTR) {
115 Ok(x) => x.as_ptr(),
116 Err(e) => {
117 tracing::warn!(
118 name = ?F::NAME_CSTR,
119 reason = ?e,
120 "could not resolve function symbol"
121 );
122 core::ptr::null_mut()
123 }
124 };
125
126 unsafe { F::from_ptr(p as _) }
127 }
128 }
129
130 #[inline(always)]
131 pub fn get_resolver<'a>() -> &'a Resolver {
132 &*GLOBAL_RESOLVER
133 }
134 }
135}
136
137pub unsafe trait FromPtr {
138 unsafe fn from_ptr(p: *const c_void) -> Self;
139}
140pub unsafe trait PFN {
141 const NAME_CSTR: &'static core::ffi::CStr;
142
143 unsafe fn from_ptr(p: *const c_void) -> Self;
144 unsafe fn from_void_fn(p: PFN_vkVoidFunction) -> Self;
145}
146pub trait StaticCallable: PFN {
147 const STATIC: Self;
148}
149
150#[implements]
151pub struct ResolvedFnCell<F: PFN, R>(R, std::sync::OnceLock<F>);
152#[implements]
153impl<F: PFN, R: ResolverInterface> ResolvedFnCell<F, R> {
154 pub const fn new(resolver: R) -> Self {
155 Self(resolver, std::sync::OnceLock::new())
156 }
157
158 pub fn resolve(&self) -> &F {
159 self.1
160 .get_or_init(|| unsafe { self.0.load_function_unconstrainted::<F>() })
161 }
162}