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
This commit is contained in:
Aaron Loucks 2019-03-15 18:41:33 -04:00
parent b570edcee2
commit adb194891f
6 changed files with 177 additions and 56 deletions

View file

@ -11,7 +11,6 @@ documentation = "https://docs.rs/ash"
[dependencies]
shared_library = "0.1.9"
lazy_static = "1"
[features]
default = []

View file

@ -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, String> =
DynamicLibrary::open(Some(&Path::new(LIB_PATH)));
}
/// Function loader
pub type Entry = EntryCustom<Arc<DynamicLibrary>>;
/// Function loader
#[derive(Clone)]
pub struct EntryCustom<L> {
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 = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetInstanceProcAddr.html>"]
fn get_instance_proc_addr(
&self,
instance: vk::Instance,
@ -177,6 +192,41 @@ pub trait EntryV1_1: EntryV1_0 {
}
}
}
impl EntryCustom<Arc<DynamicLibrary>> {
/// ```rust
/// # #[macro_use]
/// # extern crate ash;
/// use ash::{vk, Entry, version::EntryV1_0};
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// 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<Entry, LoadingError> {
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<L> EntryCustom<L> {
pub fn new_custom<Open, Load>(open: Open, mut load: Load) -> Result<Self, LoadingError>
where
@ -201,21 +251,45 @@ impl<L> EntryCustom<L> {
lib,
})
}
}
impl Entry {
pub fn new() -> Result<Self, LoadingError> {
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 = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceVersion.html>"]
/// ```rust
/// # #[macro_use]
/// # extern crate ash;
/// # use ash::Entry;
/// # fn main() -> Result<(), Box<std::error::Error>> {
/// 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<Option<u32>> {
unsafe {
let mut api_version = 0;
let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
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)
}
}
}
}

View file

@ -1,9 +1,32 @@
#[macro_use]
extern crate lazy_static;
//! # Vulkan API
//!
//! <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/index.html>
//!
//! ## Examples
//!
//! ```rust
//! # #[macro_use]
//! # extern crate ash;
//! use ash::{vk, Entry, version::EntryV1_0};
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! 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;

View file

@ -20,24 +20,28 @@ pub trait Handle {
fn as_raw(self) -> u64;
fn from_raw(u64) -> Self;
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_MAKE_VERSION.html>"]
#[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 = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_VERSION_MAJOR.html>"]
#[macro_export]
macro_rules! vk_version_major {
( $ major : expr ) => {
($major as u32) >> 22
};
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_VERSION_MINOR.html>"]
#[macro_export]
macro_rules! vk_version_minor {
( $ minor : expr ) => {
(($minor as u32) >> 12) & 0x3ff
};
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_VERSION_PATCH.html>"]
#[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 <<devsandqueues-lost-device>>")
}
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 {

View file

@ -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"
);
}

View file

@ -179,6 +179,7 @@ pub fn handle_nondispatchable_macro() -> Tokens {
}
pub fn vk_version_macros() -> Tokens {
quote! {
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_MAKE_VERSION.html>"]
#[macro_export]
macro_rules! vk_make_version {
($major:expr, $minor:expr, $patch:expr) => {
@ -186,6 +187,7 @@ pub fn vk_version_macros() -> Tokens {
};
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_VERSION_MAJOR.html>"]
#[macro_export]
macro_rules! vk_version_major {
($major:expr) => {
@ -193,6 +195,7 @@ pub fn vk_version_macros() -> Tokens {
};
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_VERSION_MINOR.html>"]
#[macro_export]
macro_rules! vk_version_minor {
($minor:expr) => {
@ -200,6 +203,7 @@ pub fn vk_version_macros() -> Tokens {
};
}
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_VERSION_PATCH.html>"]
#[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 {