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:
parent
b570edcee2
commit
adb194891f
|
@ -11,7 +11,6 @@ documentation = "https://docs.rs/ash"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
shared_library = "0.1.9"
|
shared_library = "0.1.9"
|
||||||
lazy_static = "1"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|
112
ash/src/entry.rs
112
ash/src/entry.rs
|
@ -27,12 +27,10 @@ const LIB_PATH: &'static str = "libvulkan.so";
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
const LIB_PATH: &'static str = "libvulkan.dylib";
|
const LIB_PATH: &'static str = "libvulkan.dylib";
|
||||||
|
|
||||||
lazy_static! {
|
/// Function loader
|
||||||
static ref VK_LIB: Result<DynamicLibrary, String> =
|
|
||||||
DynamicLibrary::open(Some(&Path::new(LIB_PATH)));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Entry = EntryCustom<Arc<DynamicLibrary>>;
|
pub type Entry = EntryCustom<Arc<DynamicLibrary>>;
|
||||||
|
|
||||||
|
/// Function loader
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EntryCustom<L> {
|
pub struct EntryCustom<L> {
|
||||||
static_fn: vk::StaticFn,
|
static_fn: vk::StaticFn,
|
||||||
|
@ -46,6 +44,22 @@ pub enum LoadingError {
|
||||||
LibraryLoadError(String),
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum InstanceError {
|
pub enum InstanceError {
|
||||||
LoadError(Vec<&'static str>),
|
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(
|
fn get_instance_proc_addr(
|
||||||
&self,
|
&self,
|
||||||
instance: vk::Instance,
|
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> {
|
impl<L> EntryCustom<L> {
|
||||||
pub fn new_custom<Open, Load>(open: Open, mut load: Load) -> Result<Self, LoadingError>
|
pub fn new_custom<Open, Load>(open: Open, mut load: Load) -> Result<Self, LoadingError>
|
||||||
where
|
where
|
||||||
|
@ -201,21 +251,45 @@ impl<L> EntryCustom<L> {
|
||||||
lib,
|
lib,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Entry {
|
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceVersion.html>"]
|
||||||
pub fn new() -> Result<Self, LoadingError> {
|
/// ```rust
|
||||||
Self::new_custom(
|
/// # #[macro_use]
|
||||||
|| {
|
/// # extern crate ash;
|
||||||
DynamicLibrary::open(Some(&Path::new(LIB_PATH)))
|
/// # use ash::Entry;
|
||||||
.map_err(|err| LoadingError::LibraryLoadError(err.clone()))
|
/// # fn main() -> Result<(), Box<std::error::Error>> {
|
||||||
.map(|dl| Arc::new(dl))
|
/// let entry = Entry::new()?;
|
||||||
},
|
/// match entry.try_enumerate_instance_version()? {
|
||||||
|vk_lib, name| unsafe {
|
/// // Vulkan 1.1+
|
||||||
vk_lib
|
/// Some(version) => {
|
||||||
.symbol(&*name.to_string_lossy())
|
/// let major = vk_version_major!(version);
|
||||||
.unwrap_or(ptr::null_mut())
|
/// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,32 @@
|
||||||
#[macro_use]
|
//! # Vulkan API
|
||||||
extern crate lazy_static;
|
//!
|
||||||
|
//! <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;
|
extern crate shared_library;
|
||||||
|
|
||||||
pub use device::Device;
|
pub use device::Device;
|
||||||
pub use entry::{Entry, InstanceError, LoadingError};
|
pub use entry::{Entry, EntryCustom, InstanceError, LoadingError};
|
||||||
pub use instance::Instance;
|
pub use instance::Instance;
|
||||||
|
|
||||||
mod device;
|
mod device;
|
||||||
|
|
|
@ -20,24 +20,28 @@ pub trait Handle {
|
||||||
fn as_raw(self) -> u64;
|
fn as_raw(self) -> u64;
|
||||||
fn from_raw(u64) -> Self;
|
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_export]
|
||||||
macro_rules! vk_make_version {
|
macro_rules! vk_make_version {
|
||||||
( $ major : expr , $ minor : expr , $ patch : expr ) => {
|
( $ major : expr , $ minor : expr , $ patch : expr ) => {
|
||||||
(($major as u32) << 22) | (($minor as u32) << 12) | $patch as u32
|
(($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_export]
|
||||||
macro_rules! vk_version_major {
|
macro_rules! vk_version_major {
|
||||||
( $ major : expr ) => {
|
( $ major : expr ) => {
|
||||||
($major as u32) >> 22
|
($major as u32) >> 22
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_VERSION_MINOR.html>"]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vk_version_minor {
|
macro_rules! vk_version_minor {
|
||||||
( $ minor : expr ) => {
|
( $ minor : expr ) => {
|
||||||
(($minor as u32) >> 12) & 0x3ff
|
(($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_export]
|
||||||
macro_rules! vk_version_patch {
|
macro_rules! vk_version_patch {
|
||||||
( $ minor : expr ) => {
|
( $ minor : expr ) => {
|
||||||
|
@ -41349,34 +41353,24 @@ impl ::std::error::Error for Result {
|
||||||
impl fmt::Display for Result {
|
impl fmt::Display for Result {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let name = match *self {
|
let name = match *self {
|
||||||
Result::SUCCESS => Some("Command completed successfully"),
|
Result::SUCCESS => Some(stringify!(SUCCESS)),
|
||||||
Result::NOT_READY => Some("A fence or query has not yet completed"),
|
Result::NOT_READY => Some(stringify!(NOT_READY)),
|
||||||
Result::TIMEOUT => Some("A wait operation has not completed in the specified time"),
|
Result::TIMEOUT => Some(stringify!(TIMEOUT)),
|
||||||
Result::EVENT_SET => Some("An event is signaled"),
|
Result::EVENT_SET => Some(stringify!(EVENT_SET)),
|
||||||
Result::EVENT_RESET => Some("An event is unsignaled"),
|
Result::EVENT_RESET => Some(stringify!(EVENT_RESET)),
|
||||||
Result::INCOMPLETE => Some("A return array was too small for the result"),
|
Result::INCOMPLETE => Some(stringify!(INCOMPLETE)),
|
||||||
Result::ERROR_OUT_OF_HOST_MEMORY => Some("A host memory allocation has failed"),
|
Result::ERROR_OUT_OF_HOST_MEMORY => Some(stringify!(ERROR_OUT_OF_HOST_MEMORY)),
|
||||||
Result::ERROR_OUT_OF_DEVICE_MEMORY => Some("A device memory allocation has failed"),
|
Result::ERROR_OUT_OF_DEVICE_MEMORY => Some(stringify!(ERROR_OUT_OF_DEVICE_MEMORY)),
|
||||||
Result::ERROR_INITIALIZATION_FAILED => Some("Initialization of a object has failed"),
|
Result::ERROR_INITIALIZATION_FAILED => Some(stringify!(ERROR_INITIALIZATION_FAILED)),
|
||||||
Result::ERROR_DEVICE_LOST => {
|
Result::ERROR_DEVICE_LOST => Some(stringify!(ERROR_DEVICE_LOST)),
|
||||||
Some("The logical device has been lost. See <<devsandqueues-lost-device>>")
|
Result::ERROR_MEMORY_MAP_FAILED => Some(stringify!(ERROR_MEMORY_MAP_FAILED)),
|
||||||
}
|
Result::ERROR_LAYER_NOT_PRESENT => Some(stringify!(ERROR_LAYER_NOT_PRESENT)),
|
||||||
Result::ERROR_MEMORY_MAP_FAILED => Some("Mapping of a memory object has failed"),
|
Result::ERROR_EXTENSION_NOT_PRESENT => Some(stringify!(ERROR_EXTENSION_NOT_PRESENT)),
|
||||||
Result::ERROR_LAYER_NOT_PRESENT => Some("Layer specified does not exist"),
|
Result::ERROR_FEATURE_NOT_PRESENT => Some(stringify!(ERROR_FEATURE_NOT_PRESENT)),
|
||||||
Result::ERROR_EXTENSION_NOT_PRESENT => Some("Extension specified does not exist"),
|
Result::ERROR_INCOMPATIBLE_DRIVER => Some(stringify!(ERROR_INCOMPATIBLE_DRIVER)),
|
||||||
Result::ERROR_FEATURE_NOT_PRESENT => {
|
Result::ERROR_TOO_MANY_OBJECTS => Some(stringify!(ERROR_TOO_MANY_OBJECTS)),
|
||||||
Some("Requested feature is not available on this device")
|
Result::ERROR_FORMAT_NOT_SUPPORTED => Some(stringify!(ERROR_FORMAT_NOT_SUPPORTED)),
|
||||||
}
|
Result::ERROR_FRAGMENTED_POOL => Some(stringify!(ERROR_FRAGMENTED_POOL)),
|
||||||
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",
|
|
||||||
),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(x) = name {
|
if let Some(x) = name {
|
||||||
|
|
|
@ -14,3 +14,17 @@ fn display_flags() {
|
||||||
fn display_enum() {
|
fn display_enum() {
|
||||||
assert_eq!(vk::ChromaLocation::MIDPOINT.to_string(), "MIDPOINT");
|
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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -179,6 +179,7 @@ pub fn handle_nondispatchable_macro() -> Tokens {
|
||||||
}
|
}
|
||||||
pub fn vk_version_macros() -> Tokens {
|
pub fn vk_version_macros() -> Tokens {
|
||||||
quote! {
|
quote! {
|
||||||
|
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VK_MAKE_VERSION.html>"]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vk_make_version {
|
macro_rules! vk_make_version {
|
||||||
($major:expr, $minor:expr, $patch:expr) => {
|
($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_export]
|
||||||
macro_rules! vk_version_major {
|
macro_rules! vk_version_major {
|
||||||
($major:expr) => {
|
($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_export]
|
||||||
macro_rules! vk_version_minor {
|
macro_rules! vk_version_minor {
|
||||||
($minor:expr) => {
|
($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_export]
|
||||||
macro_rules! vk_version_patch {
|
macro_rules! vk_version_patch {
|
||||||
($minor:expr) => {
|
($minor:expr) => {
|
||||||
|
@ -1206,7 +1210,7 @@ pub fn generate_enum<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_result(ident: Ident, _enum: &vkxml::Enumeration) -> Tokens {
|
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 {
|
let (variant_name, notation) = match *elem {
|
||||||
vkxml::EnumerationElement::Enum(ref constant) => (
|
vkxml::EnumerationElement::Enum(ref constant) => (
|
||||||
constant.name.as_str(),
|
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! {
|
quote! {
|
||||||
impl ::std::error::Error for #ident {
|
impl ::std::error::Error for #ident {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
let name = match *self {
|
let name = match *self {
|
||||||
#(#notation),*,
|
#(#description_notation),*,
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
name.unwrap_or("unknown error")
|
name.unwrap_or("unknown error")
|
||||||
|
@ -1237,7 +1254,7 @@ pub fn generate_result(ident: Ident, _enum: &vkxml::Enumeration) -> Tokens {
|
||||||
impl fmt::Display for #ident {
|
impl fmt::Display for #ident {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let name = match *self {
|
let name = match *self {
|
||||||
#(#notation2),*,
|
#(#display_notation),*,
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(x) = name {
|
if let Some(x) = name {
|
||||||
|
|
Loading…
Reference in a new issue