1#![cfg_attr(not(feature = "std"), no_std)]
58#![cfg_attr(feature = "no_std_error", feature(error_in_core))]
59
60extern crate alloc;
61
62pub mod bytecode;
63pub mod chain;
64pub mod loader;
65pub mod vk;
66
67#[cfg(feature = "window")]
68pub mod window;
69
70use alloc::boxed::Box;
71use alloc::collections::btree_set::BTreeSet;
72use alloc::sync::Arc;
73use core::ffi::c_char;
74use core::fmt;
75use core::mem;
76use core::slice;
77
78use self::loader::{Loader, LoaderError};
79use self::prelude::v1_0::*;
80use self::vk::{DeviceCommands, EntryCommands, InstanceCommands, StaticCommands};
81
82pub mod prelude {
84 pub mod v1_0 {
86 pub use crate::vk;
87 pub use crate::vk::{DeviceV1_0, EntryV1_0, InstanceV1_0};
88 pub use crate::vk::{Handle, HasBuilder};
89 pub use crate::{Device, Entry, Instance, VkResult, VkSuccessResult};
90 }
91
92 pub mod v1_1 {
94 pub use crate::prelude::v1_0::*;
95 pub use crate::vk::{DeviceV1_1, EntryV1_1, InstanceV1_1};
96 }
97
98 pub mod v1_2 {
100 pub use crate::prelude::v1_1::*;
101 pub use crate::vk::{DeviceV1_2, EntryV1_2, InstanceV1_2};
102 }
103
104 pub mod v1_3 {
106 pub use crate::prelude::v1_2::*;
107 pub use crate::vk::{DeviceV1_3, EntryV1_3, InstanceV1_3};
108 }
109
110 pub mod v1_4 {
112 pub use crate::prelude::v1_3::*;
113 pub use crate::vk::{DeviceV1_4, EntryV1_4, InstanceV1_4};
114 }
115}
116
117pub type VkResult<T> = Result<T, vk::ErrorCode>;
119pub type VkSuccessResult<T> = Result<(T, vk::SuccessCode), vk::ErrorCode>;
121
122pub trait ResultExt {
124 fn result(self) -> VkResult<()>;
126}
127
128impl ResultExt for vk::Result {
129 #[inline]
130 fn result(self) -> VkResult<()> {
131 match self {
132 vk::Result::SUCCESS => Ok(()),
133 error => Err(error.into()),
134 }
135 }
136}
137
138#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
140pub struct Version {
141 pub major: u32,
143 pub minor: u32,
145 pub patch: u32,
151}
152
153impl Version {
154 pub const V1_0_0: Version = Version::new(1, 0, 0);
156 pub const V1_1_0: Version = Version::new(1, 1, 0);
158 pub const V1_2_0: Version = Version::new(1, 2, 0);
160 pub const V1_3_0: Version = Version::new(1, 3, 0);
162 pub const V1_4_0: Version = Version::new(1, 4, 0);
164
165 pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
167 Self {
168 major,
169 minor,
170 patch,
171 }
172 }
173}
174
175impl Default for Version {
176 #[inline]
177 fn default() -> Self {
178 Self::V1_0_0
179 }
180}
181
182impl fmt::Display for Version {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
185 }
186}
187
188impl From<u32> for Version {
189 #[inline]
190 fn from(version: u32) -> Self {
191 Self::new(
192 vk::version_major(version),
193 vk::version_minor(version),
194 vk::version_patch(version),
195 )
196 }
197}
198
199impl From<Version> for u32 {
200 fn from(version: Version) -> Self {
201 vk::make_version(version.major, version.minor, version.patch)
202 }
203}
204
205impl From<(u32, u32, u32)> for Version {
206 fn from((major, minor, patch): (u32, u32, u32)) -> Self {
207 Self::new(major, minor, patch)
208 }
209}
210
211impl From<Version> for (u32, u32, u32) {
212 fn from(version: Version) -> Self {
213 (version.major, version.minor, version.patch)
214 }
215}
216
217#[derive(Clone)]
219pub struct Entry {
220 _loader: Option<Arc<dyn Loader>>,
221 static_commands: StaticCommands,
222 commands: EntryCommands,
223}
224
225impl Entry {
226 #[inline]
228 pub unsafe fn from_commands(static_commands: &StaticCommands) -> Self {
229 let load = |n| (static_commands.get_instance_proc_addr)(vk::Instance::null(), n);
230 let commands = EntryCommands::load(load);
231
232 Self {
233 _loader: None,
234 static_commands: *static_commands,
235 commands,
236 }
237 }
238
239 #[inline]
247 pub unsafe fn new(loader: impl Loader + 'static) -> Result<Self, Box<dyn LoaderError>> {
248 let loader = Arc::new(loader);
249
250 type F = extern "system" fn();
251
252 let raw = loader.load(b"vkGetInstanceProcAddr")?;
253 let get_instance_proc_addr = mem::transmute::<F, vk::PFN_vkGetInstanceProcAddr>(raw);
254
255 let raw = loader.load(b"vkGetDeviceProcAddr")?;
256 let get_device_proc_addr = mem::transmute::<F, vk::PFN_vkGetDeviceProcAddr>(raw);
257
258 let static_commands = StaticCommands {
259 get_instance_proc_addr,
260 get_device_proc_addr,
261 };
262
263 let load = |n| get_instance_proc_addr(vk::Instance::null(), n);
264 let commands = EntryCommands::load(load);
265
266 Ok(Self {
267 _loader: Some(loader),
268 static_commands,
269 commands,
270 })
271 }
272
273 #[inline]
275 pub fn version(&self) -> VkResult<Version> {
276 unsafe { get_version(self.static_commands.get_instance_proc_addr) }
277 }
278
279 #[inline]
288 pub unsafe fn create_instance(
289 &self,
290 info: &vk::InstanceCreateInfo,
291 allocator: Option<&vk::AllocationCallbacks>,
292 ) -> VkResult<Instance> {
293 let instance = EntryV1_0::create_instance(self, info, allocator)?;
294 Instance::from_created(self, info, instance)
295 }
296}
297
298impl fmt::Debug for Entry {
299 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300 write!(f, "Entry")
301 }
302}
303
304unsafe impl Send for Entry {}
305unsafe impl Sync for Entry {}
306
307#[derive(Clone)]
309pub struct Instance {
310 entry: Entry,
311 handle: vk::Instance,
312 commands: InstanceCommands,
313 version: Version,
314 extensions: BTreeSet<vk::ExtensionName>,
315 layers: BTreeSet<vk::ExtensionName>,
316}
317
318impl Instance {
319 #[inline]
321 pub unsafe fn from_created(
322 entry: &Entry,
323 info: &vk::InstanceCreateInfo,
324 instance: vk::Instance,
325 ) -> VkResult<Self> {
326 let load = |n| (entry.static_commands.get_instance_proc_addr)(instance, n);
327 let commands = InstanceCommands::load(load);
328
329 let version = get_version(entry.static_commands.get_instance_proc_addr)?;
330
331 let extensions = get_names(info.enabled_extension_count, info.enabled_extension_names);
332 let layers = get_names(info.enabled_layer_count, info.enabled_layer_names);
333
334 Ok(Self {
335 entry: entry.clone(),
336 handle: instance,
337 commands,
338 version,
339 extensions,
340 layers,
341 })
342 }
343
344 #[inline]
346 pub fn version(&self) -> Version {
347 self.version
348 }
349
350 #[inline]
352 pub fn extensions(&self) -> &BTreeSet<vk::ExtensionName> {
353 &self.extensions
354 }
355
356 #[inline]
358 pub fn layers(&self) -> &BTreeSet<vk::ExtensionName> {
359 &self.layers
360 }
361
362 #[inline]
370 pub unsafe fn create_device(
371 &self,
372 physical_device: vk::PhysicalDevice,
373 info: &vk::DeviceCreateInfo,
374 allocator: Option<&vk::AllocationCallbacks>,
375 ) -> VkResult<Device> {
376 let device = InstanceV1_0::create_device(self, physical_device, info, allocator)?;
377 Device::from_created(&self.entry, physical_device, info, device)
378 }
379}
380
381impl fmt::Debug for Instance {
382 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
383 f.debug_struct("Instance")
384 .field("handle", &self.handle)
385 .field("extensions", &self.extensions)
386 .field("layers", &self.layers)
387 .finish()
388 }
389}
390
391unsafe impl Send for Instance {}
392unsafe impl Sync for Instance {}
393
394#[derive(Clone)]
396pub struct Device {
397 handle: vk::Device,
398 commands: DeviceCommands,
399 physical_device: vk::PhysicalDevice,
400 extensions: BTreeSet<vk::ExtensionName>,
401 layers: BTreeSet<vk::ExtensionName>,
402}
403
404impl Device {
405 #[inline]
407 pub unsafe fn from_created(
408 entry: &Entry,
409 physical_device: vk::PhysicalDevice,
410 info: &vk::DeviceCreateInfo,
411 device: vk::Device,
412 ) -> VkResult<Self> {
413 let load = |n| (entry.static_commands.get_device_proc_addr)(device, n);
414 let commands = DeviceCommands::load(load);
415
416 let extensions = get_names(info.enabled_extension_count, info.enabled_extension_names);
417 let layers = get_names(info.enabled_layer_count, info.enabled_layer_names);
418
419 Ok(Self {
420 handle: device,
421 commands,
422 physical_device,
423 extensions,
424 layers,
425 })
426 }
427
428 #[inline]
430 pub fn physical_device(&self) -> vk::PhysicalDevice {
431 self.physical_device
432 }
433
434 #[inline]
436 pub fn extensions(&self) -> &BTreeSet<vk::ExtensionName> {
437 &self.extensions
438 }
439
440 #[inline]
442 pub fn layers(&self) -> &BTreeSet<vk::ExtensionName> {
443 &self.layers
444 }
445}
446
447impl fmt::Debug for Device {
448 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
449 f.debug_struct("Device")
450 .field("handle", &self.handle)
451 .field("extensions", &self.extensions)
452 .field("layers", &self.layers)
453 .finish()
454 }
455}
456
457unsafe impl Send for Device {}
458unsafe impl Sync for Device {}
459
460#[inline]
461unsafe fn get_names(
462 num_strings: u32,
463 strings: *const *const c_char,
464) -> BTreeSet<vk::ExtensionName> {
465 if strings.is_null() || num_strings == 0 {
466 return BTreeSet::new();
467 }
468
469 slice::from_raw_parts(strings, num_strings as usize)
470 .iter()
471 .map(|s| vk::ExtensionName::from_ptr(*s))
472 .collect()
473}
474
475#[inline]
476unsafe fn get_version(get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr) -> VkResult<Version> {
477 let name = c"vkEnumerateInstanceVersion".as_ptr();
478 let raw = (get_instance_proc_addr)(vk::Instance::null(), name);
479 let enumerate: Option<vk::PFN_vkEnumerateInstanceVersion> = mem::transmute(raw);
480 if let Some(enumerate) = enumerate {
481 let mut version = 0;
482 match unsafe { enumerate(&mut version) } {
483 vk::Result::SUCCESS => Ok(Version::from(version)),
484 error => Err(error.into()),
485 }
486 } else {
487 Ok(Version::V1_0_0)
488 }
489}