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