From adb194891f212e789caa1a3c53aeddcbf0d46b2c Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Fri, 15 Mar 2019 18:41:33 -0400 Subject: [PATCH] Add Khronos doc links and other ergonomic cleanup * Khronos doc links are now automatically generated in vk.rs * Added doc links to all other non-generated functions * Implemented std::error::Error for LoadingError * Made EntryCustom public in addition to the Entry typedef so that rustdoc no longer ignores it * Moved Entry::new into EntryCustom (non-breaking) * Added EntryCustom::try_enumerate_instance_version. The EntryV1_1 trait is not implemented for any type. Even if it were, the function would panic for Vulkan 1.0 implementations * Added entry and instance creation example to lib docs * Updated the Display impl for vk::Result so that it matches other bitmask and enum conventions * Removed lazy_static dependency because it was no longer being referenced --- ash/Cargo.toml | 1 - ash/src/entry.rs | 114 +++++++++++++++++++++++++++++++++++-------- ash/src/lib.rs | 29 +++++++++-- ash/src/vk.rs | 50 +++++++++---------- ash/tests/display.rs | 14 ++++++ generator/src/lib.rs | 25 ++++++++-- 6 files changed, 177 insertions(+), 56 deletions(-) diff --git a/ash/Cargo.toml b/ash/Cargo.toml index c886013..45f5b2b 100644 --- a/ash/Cargo.toml +++ b/ash/Cargo.toml @@ -11,7 +11,6 @@ documentation = "https://docs.rs/ash" [dependencies] shared_library = "0.1.9" -lazy_static = "1" [features] default = [] diff --git a/ash/src/entry.rs b/ash/src/entry.rs index a8cc875..4f043ba 100644 --- a/ash/src/entry.rs +++ b/ash/src/entry.rs @@ -27,12 +27,10 @@ const LIB_PATH: &'static str = "libvulkan.so"; #[cfg(any(target_os = "macos", target_os = "ios"))] const LIB_PATH: &'static str = "libvulkan.dylib"; -lazy_static! { - static ref VK_LIB: Result = - DynamicLibrary::open(Some(&Path::new(LIB_PATH))); -} - +/// Function loader pub type Entry = EntryCustom>; + +/// Function loader #[derive(Clone)] pub struct EntryCustom { static_fn: vk::StaticFn, @@ -46,6 +44,22 @@ pub enum LoadingError { LibraryLoadError(String), } +impl fmt::Display for LoadingError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "LoadingError::{:?}", self) + } +} + +impl Error for LoadingError { + fn description(&self) -> &str { + "LoadingError" + } + + fn cause(&self) -> Option<&Error> { + None + } +} + #[derive(Debug)] pub enum InstanceError { LoadError(Vec<&'static str>), @@ -125,6 +139,7 @@ pub trait EntryV1_0 { } } + #[doc = ""] fn get_instance_proc_addr( &self, instance: vk::Instance, @@ -177,6 +192,41 @@ pub trait EntryV1_1: EntryV1_0 { } } } + +impl EntryCustom> { + /// ```rust + /// # #[macro_use] + /// # extern crate ash; + /// use ash::{vk, Entry, version::EntryV1_0}; + /// # fn main() -> Result<(), Box> { + /// let entry = Entry::new()?; + /// let app_info = vk::ApplicationInfo { + /// api_version: vk_make_version!(1, 0, 0), + /// ..Default::default() + /// }; + /// let create_info = vk::InstanceCreateInfo { + /// p_application_info: &app_info, + /// ..Default::default() + /// }; + /// let instance = unsafe { entry.create_instance(&create_info, None)? }; + /// # Ok(()) } + /// ``` + pub fn new() -> Result { + Self::new_custom( + || { + DynamicLibrary::open(Some(&Path::new(LIB_PATH))) + .map_err(|err| LoadingError::LibraryLoadError(err.clone())) + .map(|dl| Arc::new(dl)) + }, + |vk_lib, name| unsafe { + vk_lib + .symbol(&*name.to_string_lossy()) + .unwrap_or(ptr::null_mut()) + }, + ) + } +} + impl EntryCustom { pub fn new_custom(open: Open, mut load: Load) -> Result where @@ -201,21 +251,45 @@ impl EntryCustom { lib, }) } -} -impl Entry { - pub fn new() -> Result { - Self::new_custom( - || { - DynamicLibrary::open(Some(&Path::new(LIB_PATH))) - .map_err(|err| LoadingError::LibraryLoadError(err.clone())) - .map(|dl| Arc::new(dl)) - }, - |vk_lib, name| unsafe { - vk_lib - .symbol(&*name.to_string_lossy()) - .unwrap_or(ptr::null_mut()) - }, - ) + #[doc = ""] + /// ```rust + /// # #[macro_use] + /// # extern crate ash; + /// # use ash::Entry; + /// # fn main() -> Result<(), Box> { + /// let entry = Entry::new()?; + /// match entry.try_enumerate_instance_version()? { + /// // Vulkan 1.1+ + /// Some(version) => { + /// let major = vk_version_major!(version); + /// let minor = vk_version_minor!(version); + /// let patch = vk_version_patch!(version); + /// }, + /// // Vulkan 1.0 + /// None => {}, + /// } + /// # Ok(()) } + /// ``` + pub fn try_enumerate_instance_version(&self) -> VkResult> { + unsafe { + let mut api_version = 0; + let enumerate_instance_version: Option = { + let name = b"vkEnumerateInstanceVersion\0".as_ptr() as *const _; + mem::transmute( + self.static_fn() + .get_instance_proc_addr(vk::Instance::null(), name), + ) + }; + if let Some(enumerate_instance_version) = enumerate_instance_version { + let err_code = (enumerate_instance_version)(&mut api_version); + match err_code { + vk::Result::SUCCESS => Ok(Some(api_version)), + _ => Err(err_code), + } + } else { + Ok(None) + } + } } } diff --git a/ash/src/lib.rs b/ash/src/lib.rs index 43581dd..03b0801 100644 --- a/ash/src/lib.rs +++ b/ash/src/lib.rs @@ -1,9 +1,32 @@ -#[macro_use] -extern crate lazy_static; +//! # Vulkan API +//! +//! +//! +//! ## Examples +//! +//! ```rust +//! # #[macro_use] +//! # extern crate ash; +//! use ash::{vk, Entry, version::EntryV1_0}; +//! # fn main() -> Result<(), Box> { +//! let entry = Entry::new()?; +//! let app_info = vk::ApplicationInfo { +//! api_version: vk_make_version!(1, 0, 0), +//! ..Default::default() +//! }; +//! let create_info = vk::InstanceCreateInfo { +//! p_application_info: &app_info, +//! ..Default::default() +//! }; +//! let instance = unsafe { entry.create_instance(&create_info, None)? }; +//! # Ok(()) } +//! ``` +//! + extern crate shared_library; pub use device::Device; -pub use entry::{Entry, InstanceError, LoadingError}; +pub use entry::{Entry, EntryCustom, InstanceError, LoadingError}; pub use instance::Instance; mod device; diff --git a/ash/src/vk.rs b/ash/src/vk.rs index 712f5d7..a843d70 100644 --- a/ash/src/vk.rs +++ b/ash/src/vk.rs @@ -20,24 +20,28 @@ pub trait Handle { fn as_raw(self) -> u64; fn from_raw(u64) -> Self; } +#[doc = ""] #[macro_export] macro_rules! vk_make_version { ( $ major : expr , $ minor : expr , $ patch : expr ) => { (($major as u32) << 22) | (($minor as u32) << 12) | $patch as u32 }; } +#[doc = ""] #[macro_export] macro_rules! vk_version_major { ( $ major : expr ) => { ($major as u32) >> 22 }; } +#[doc = ""] #[macro_export] macro_rules! vk_version_minor { ( $ minor : expr ) => { (($minor as u32) >> 12) & 0x3ff }; } +#[doc = ""] #[macro_export] macro_rules! vk_version_patch { ( $ minor : expr ) => { @@ -41349,34 +41353,24 @@ impl ::std::error::Error for Result { impl fmt::Display for Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let name = match *self { - Result::SUCCESS => Some("Command completed successfully"), - Result::NOT_READY => Some("A fence or query has not yet completed"), - Result::TIMEOUT => Some("A wait operation has not completed in the specified time"), - Result::EVENT_SET => Some("An event is signaled"), - Result::EVENT_RESET => Some("An event is unsignaled"), - Result::INCOMPLETE => Some("A return array was too small for the result"), - Result::ERROR_OUT_OF_HOST_MEMORY => Some("A host memory allocation has failed"), - Result::ERROR_OUT_OF_DEVICE_MEMORY => Some("A device memory allocation has failed"), - Result::ERROR_INITIALIZATION_FAILED => Some("Initialization of a object has failed"), - Result::ERROR_DEVICE_LOST => { - Some("The logical device has been lost. See <>") - } - Result::ERROR_MEMORY_MAP_FAILED => Some("Mapping of a memory object has failed"), - Result::ERROR_LAYER_NOT_PRESENT => Some("Layer specified does not exist"), - Result::ERROR_EXTENSION_NOT_PRESENT => Some("Extension specified does not exist"), - Result::ERROR_FEATURE_NOT_PRESENT => { - Some("Requested feature is not available on this device") - } - Result::ERROR_INCOMPATIBLE_DRIVER => Some("Unable to find a Vulkan driver"), - Result::ERROR_TOO_MANY_OBJECTS => { - Some("Too many objects of the type have already been created") - } - Result::ERROR_FORMAT_NOT_SUPPORTED => { - Some("Requested format is not supported on this device") - } - Result::ERROR_FRAGMENTED_POOL => Some( - "A requested pool allocation has failed due to fragmentation of the pool\'s memory", - ), + Result::SUCCESS => Some(stringify!(SUCCESS)), + Result::NOT_READY => Some(stringify!(NOT_READY)), + Result::TIMEOUT => Some(stringify!(TIMEOUT)), + Result::EVENT_SET => Some(stringify!(EVENT_SET)), + Result::EVENT_RESET => Some(stringify!(EVENT_RESET)), + Result::INCOMPLETE => Some(stringify!(INCOMPLETE)), + Result::ERROR_OUT_OF_HOST_MEMORY => Some(stringify!(ERROR_OUT_OF_HOST_MEMORY)), + Result::ERROR_OUT_OF_DEVICE_MEMORY => Some(stringify!(ERROR_OUT_OF_DEVICE_MEMORY)), + Result::ERROR_INITIALIZATION_FAILED => Some(stringify!(ERROR_INITIALIZATION_FAILED)), + Result::ERROR_DEVICE_LOST => Some(stringify!(ERROR_DEVICE_LOST)), + Result::ERROR_MEMORY_MAP_FAILED => Some(stringify!(ERROR_MEMORY_MAP_FAILED)), + Result::ERROR_LAYER_NOT_PRESENT => Some(stringify!(ERROR_LAYER_NOT_PRESENT)), + Result::ERROR_EXTENSION_NOT_PRESENT => Some(stringify!(ERROR_EXTENSION_NOT_PRESENT)), + Result::ERROR_FEATURE_NOT_PRESENT => Some(stringify!(ERROR_FEATURE_NOT_PRESENT)), + Result::ERROR_INCOMPATIBLE_DRIVER => Some(stringify!(ERROR_INCOMPATIBLE_DRIVER)), + Result::ERROR_TOO_MANY_OBJECTS => Some(stringify!(ERROR_TOO_MANY_OBJECTS)), + Result::ERROR_FORMAT_NOT_SUPPORTED => Some(stringify!(ERROR_FORMAT_NOT_SUPPORTED)), + Result::ERROR_FRAGMENTED_POOL => Some(stringify!(ERROR_FRAGMENTED_POOL)), _ => None, }; if let Some(x) = name { diff --git a/ash/tests/display.rs b/ash/tests/display.rs index 7f2eb1d..7a510bd 100644 --- a/ash/tests/display.rs +++ b/ash/tests/display.rs @@ -14,3 +14,17 @@ fn display_flags() { fn display_enum() { assert_eq!(vk::ChromaLocation::MIDPOINT.to_string(), "MIDPOINT"); } + +#[test] +fn display_result() { + assert_eq!(vk::Result::SUCCESS.to_string(), "SUCCESS"); +} + +#[test] +fn error_result_description() { + use std::error::Error; + assert_eq!( + vk::Result::SUCCESS.description(), + "Command completed successfully" + ); +} diff --git a/generator/src/lib.rs b/generator/src/lib.rs index 06a892d..858e8db 100644 --- a/generator/src/lib.rs +++ b/generator/src/lib.rs @@ -179,6 +179,7 @@ pub fn handle_nondispatchable_macro() -> Tokens { } pub fn vk_version_macros() -> Tokens { quote! { + #[doc = ""] #[macro_export] macro_rules! vk_make_version { ($major:expr, $minor:expr, $patch:expr) => { @@ -186,6 +187,7 @@ pub fn vk_version_macros() -> Tokens { }; } + #[doc = ""] #[macro_export] macro_rules! vk_version_major { ($major:expr) => { @@ -193,6 +195,7 @@ pub fn vk_version_macros() -> Tokens { }; } + #[doc = ""] #[macro_export] macro_rules! vk_version_minor { ($minor:expr) => { @@ -200,6 +203,7 @@ pub fn vk_version_macros() -> Tokens { }; } + #[doc = ""] #[macro_export] macro_rules! vk_version_patch { ($minor:expr) => { @@ -1206,7 +1210,7 @@ pub fn generate_enum<'a>( } pub fn generate_result(ident: Ident, _enum: &vkxml::Enumeration) -> Tokens { - let notation = _enum.elements.iter().filter_map(|elem| { + let description_notation = _enum.elements.iter().filter_map(|elem| { let (variant_name, notation) = match *elem { vkxml::EnumerationElement::Enum(ref constant) => ( constant.name.as_str(), @@ -1223,12 +1227,25 @@ pub fn generate_result(ident: Ident, _enum: &vkxml::Enumeration) -> Tokens { }) }); - let notation2 = notation.clone(); + let display_notation = _enum.elements.iter().filter_map(|elem| { + let variant_name = match *elem { + vkxml::EnumerationElement::Enum(ref constant) => constant.name.as_str(), + _ => { + return None; + } + }; + + let variant_ident = variant_ident(&_enum.name, variant_name); + Some(quote! { + #ident::#variant_ident => Some(stringify!(#variant_ident)) + }) + }); + quote! { impl ::std::error::Error for #ident { fn description(&self) -> &str { let name = match *self { - #(#notation),*, + #(#description_notation),*, _ => None, }; name.unwrap_or("unknown error") @@ -1237,7 +1254,7 @@ pub fn generate_result(ident: Ident, _enum: &vkxml::Enumeration) -> Tokens { impl fmt::Display for #ident { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let name = match *self { - #(#notation2),*, + #(#display_notation),*, _ => None, }; if let Some(x) = name {