Support linking Vulkan directly (#457)
* Mark EntryCustom::new_custom as unsafe Passing a badly-behaved `load` function can invoke undefined behavior. * Document required feature for Entry * Support linking Vulkan directly This is the preferred pattern in most environments when an application cannot function without Vulkan, as it saves the libloading dependency, eliminates an error case, and makes the Vulkan dependency visible to the OS. * Rename libloading feature to "loaded" * Link by default * Guide users towards linking the loader directly * Remove unnecessary error type InstanceError::LoadError was never constructed. * Unify entry types Simplifies the interface and allows a bunch of code to become monomorphic.
This commit is contained in:
parent
1b4c82e1d6
commit
aa7b429f4f
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
|||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --workspace --all-targets
|
||||
args: --workspace --all-targets --all-features
|
||||
|
||||
generated:
|
||||
name: Generated
|
||||
|
@ -47,6 +47,8 @@ jobs:
|
|||
name: Test Suite
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Vulkan loader
|
||||
run: sudo apt-get install libvulkan-dev
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
|
|
@ -219,6 +219,11 @@ pub fn create_command_pool(&self,
|
|||
let pool = device.create_command_pool(&pool_create_info).unwrap();
|
||||
```
|
||||
|
||||
### Optional linking
|
||||
|
||||
The default `linked` cargo feature will link your binary with the Vulkan loader directly and expose the infallible `Entry::new`.
|
||||
If your application can handle Vulkan being missing at runtime, you can instead enable the `loaded` feature to dynamically load Vulkan with `Entry::load`.
|
||||
|
||||
## Example
|
||||
You can find the examples [here](https://github.com/MaikKlein/ash/tree/master/examples).
|
||||
All examples currently require: the LunarG Validation layers and a Vulkan library that is visible in your `PATH`. An easy way to get started is to use the [LunarG Vulkan SDK](https://lunarg.com/vulkan-sdk/)
|
||||
|
|
|
@ -15,7 +15,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.build(&events_loop)?;
|
||||
|
||||
unsafe {
|
||||
let entry = ash::Entry::new()?;
|
||||
let entry = ash::Entry::new();
|
||||
let surface_extensions = ash_window::enumerate_required_extensions(&window)?;
|
||||
let instance_extensions = surface_extensions
|
||||
.iter()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ash::{extensions::khr, prelude::*, vk, EntryCustom, Instance};
|
||||
use ash::{extensions::khr, prelude::*, vk, Entry, Instance};
|
||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
||||
use std::ffi::CStr;
|
||||
|
||||
|
@ -14,8 +14,8 @@ use ash::extensions::ext; // portability extensions
|
|||
/// In order for the created [`vk::SurfaceKHR`] to be valid for the duration of its
|
||||
/// usage, the [`Instance`] this was called on must be dropped later than the
|
||||
/// resulting [`vk::SurfaceKHR`].
|
||||
pub unsafe fn create_surface<L>(
|
||||
entry: &EntryCustom<L>,
|
||||
pub unsafe fn create_surface(
|
||||
entry: &Entry,
|
||||
instance: &Instance,
|
||||
window_handle: &dyn HasRawWindowHandle,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
|
|
|
@ -14,7 +14,15 @@ edition = "2018"
|
|||
libloading = { version = "0.7", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["libloading"]
|
||||
default = ["linked"]
|
||||
# Link the Vulkan loader at compile time.
|
||||
linked = []
|
||||
# Support searching for the Vulkan loader manually at runtime.
|
||||
loaded = ["libloading"]
|
||||
|
||||
[package.metadata.release]
|
||||
no-dev-version = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
|
24
ash/build.rs
Normal file
24
ash/build.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
fn main() {
|
||||
#[cfg(feature = "linked")]
|
||||
{
|
||||
use std::env;
|
||||
|
||||
let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
|
||||
let target_pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap();
|
||||
|
||||
println!("cargo:rerun-if-env-changed=VULKAN_SDK");
|
||||
if let Ok(var) = env::var("VULKAN_SDK") {
|
||||
let suffix = match (&*target_family, &*target_pointer_width) {
|
||||
("windows", "32") => "Lib32",
|
||||
("windows", "64") => "Lib",
|
||||
_ => "lib",
|
||||
};
|
||||
println!("cargo:rustc-link-search={}/{}", var, suffix);
|
||||
}
|
||||
let lib = match &*target_family {
|
||||
"windows" => "vulkan-1",
|
||||
_ => "vulkan",
|
||||
};
|
||||
println!("cargo:rustc-link-lib={}", lib);
|
||||
}
|
||||
}
|
219
ash/src/entry.rs
219
ash/src/entry.rs
|
@ -2,41 +2,137 @@ use crate::instance::Instance;
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use std::error::Error;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "loaded")]
|
||||
use std::ffi::OsStr;
|
||||
use std::mem;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
#[cfg(feature = "loaded")]
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Holds a custom type `L` to load symbols from (usually a handle to a `dlopen`ed library),
|
||||
/// the [`vkGetInstanceProcAddr`][vk::StaticFn::get_instance_proc_addr()] loader function from
|
||||
/// this library (in [`vk::StaticFn`]), and Vulkan's "entry point" functions (resolved with `NULL`
|
||||
/// `instance`) as listed in [`vkGetInstanceProcAddr`'s description].
|
||||
///
|
||||
/// [`vkGetInstanceProcAddr`'s description]: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html#_description
|
||||
#[cfg(feature = "loaded")]
|
||||
use libloading::Library;
|
||||
|
||||
/// Holds the Vulkan functions independent of a particular instance
|
||||
#[derive(Clone)]
|
||||
pub struct EntryCustom<L> {
|
||||
pub struct Entry {
|
||||
static_fn: vk::StaticFn,
|
||||
entry_fn_1_0: vk::EntryFnV1_0,
|
||||
entry_fn_1_1: vk::EntryFnV1_1,
|
||||
entry_fn_1_2: vk::EntryFnV1_2,
|
||||
lib: L,
|
||||
#[cfg(feature = "loaded")]
|
||||
_lib_guard: Option<Arc<Library>>,
|
||||
}
|
||||
|
||||
/// Vulkan core 1.0
|
||||
#[allow(non_camel_case_types)]
|
||||
impl<L> EntryCustom<L> {
|
||||
pub fn new_custom<Load>(
|
||||
mut lib: L,
|
||||
mut load: Load,
|
||||
) -> std::result::Result<Self, MissingEntryPoint>
|
||||
where
|
||||
Load: FnMut(&mut L, &::std::ffi::CStr) -> *const c_void,
|
||||
{
|
||||
// Bypass the normal StaticFn::load so we can return an error
|
||||
let static_fn = vk::StaticFn::load_checked(|name| load(&mut lib, name))?;
|
||||
impl Entry {
|
||||
/// Load entry points from a Vulkan loader linked at compile time
|
||||
///
|
||||
/// Note that instance/device functions are still fetched via `vkGetInstanceProcAddr` and
|
||||
/// `vkGetDeviceProcAddr` for maximum performance.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use ash::{vk, Entry};
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let entry = Entry::new();
|
||||
/// let app_info = vk::ApplicationInfo {
|
||||
/// api_version: vk::make_api_version(0, 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(()) }
|
||||
/// ```
|
||||
#[cfg(feature = "linked")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "linked")))]
|
||||
pub fn new() -> Self {
|
||||
// Sound because we're linking to Vulkan, which provides a vkGetInstanceProcAddr that has
|
||||
// defined behavior in this use.
|
||||
unsafe {
|
||||
Self::from_static_fn(vk::StaticFn {
|
||||
get_instance_proc_addr: vkGetInstanceProcAddr,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Load default Vulkan library for the current platform
|
||||
///
|
||||
/// # Safety
|
||||
/// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
|
||||
/// for [`Library::new()`] and [`Library::get()`] apply here.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use ash::{vk, Entry};
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let entry = unsafe { Entry::load()? };
|
||||
/// let app_info = vk::ApplicationInfo {
|
||||
/// api_version: vk::make_api_version(0, 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(()) }
|
||||
/// ```
|
||||
#[cfg(feature = "loaded")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
|
||||
pub unsafe fn load() -> Result<Self, LoadingError> {
|
||||
#[cfg(windows)]
|
||||
const LIB_PATH: &str = "vulkan-1.dll";
|
||||
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "macos", target_os = "ios", target_os = "android"))
|
||||
))]
|
||||
const LIB_PATH: &str = "libvulkan.so.1";
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
const LIB_PATH: &str = "libvulkan.so";
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
const LIB_PATH: &str = "libvulkan.dylib";
|
||||
|
||||
Self::load_from(LIB_PATH)
|
||||
}
|
||||
|
||||
/// Load Vulkan library at `path`
|
||||
///
|
||||
/// # Safety
|
||||
/// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
|
||||
/// for [`Library::new()`] and [`Library::get()`] apply here.
|
||||
#[cfg(feature = "loaded")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
|
||||
pub unsafe fn load_from(path: impl AsRef<OsStr>) -> Result<Self, LoadingError> {
|
||||
let lib = Library::new(path)
|
||||
.map_err(LoadingError::LibraryLoadFailure)
|
||||
.map(Arc::new)?;
|
||||
|
||||
let static_fn = vk::StaticFn::load_checked(|name| {
|
||||
lib.get(name.to_bytes_with_nul())
|
||||
.map(|symbol| *symbol)
|
||||
.unwrap_or(ptr::null_mut())
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
_lib_guard: Some(lib),
|
||||
..Self::from_static_fn(static_fn)
|
||||
})
|
||||
}
|
||||
|
||||
/// Load entry points based on an already-loaded [`vk::StaticFn`]
|
||||
///
|
||||
/// # Safety
|
||||
/// `static_fn` must contain valid function pointers that comply with the semantics specified by
|
||||
/// Vulkan 1.0, which must remain valid for at least the lifetime of the returned [`Entry`].
|
||||
pub unsafe fn from_static_fn(static_fn: vk::StaticFn) -> Self {
|
||||
let load_fn = |name: &std::ffi::CStr| unsafe {
|
||||
mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr()))
|
||||
};
|
||||
|
@ -44,13 +140,14 @@ impl<L> EntryCustom<L> {
|
|||
let entry_fn_1_1 = vk::EntryFnV1_1::load(load_fn);
|
||||
let entry_fn_1_2 = vk::EntryFnV1_2::load(load_fn);
|
||||
|
||||
Ok(EntryCustom {
|
||||
Self {
|
||||
static_fn,
|
||||
entry_fn_1_0,
|
||||
entry_fn_1_1,
|
||||
entry_fn_1_2,
|
||||
lib,
|
||||
})
|
||||
#[cfg(feature = "loaded")]
|
||||
_lib_guard: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
|
||||
|
@ -65,7 +162,7 @@ impl<L> EntryCustom<L> {
|
|||
/// ```no_run
|
||||
/// # use ash::{Entry, vk};
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let entry = unsafe { Entry::new() }?;
|
||||
/// let entry = Entry::new();
|
||||
/// match entry.try_enumerate_instance_version()? {
|
||||
/// // Vulkan 1.1+
|
||||
/// Some(version) => {
|
||||
|
@ -107,7 +204,7 @@ impl<L> EntryCustom<L> {
|
|||
&self,
|
||||
create_info: &vk::InstanceCreateInfo,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> Result<Instance, InstanceError> {
|
||||
) -> VkResult<Instance> {
|
||||
let mut instance = mem::zeroed();
|
||||
self.entry_fn_1_0
|
||||
.create_instance(
|
||||
|
@ -115,8 +212,7 @@ impl<L> EntryCustom<L> {
|
|||
allocation_callbacks.as_raw_ptr(),
|
||||
&mut instance,
|
||||
)
|
||||
.result()
|
||||
.map_err(InstanceError::VkError)?;
|
||||
.result()?;
|
||||
Ok(Instance::load(&self.static_fn, instance))
|
||||
}
|
||||
|
||||
|
@ -154,7 +250,7 @@ impl<L> EntryCustom<L> {
|
|||
|
||||
/// Vulkan core 1.1
|
||||
#[allow(non_camel_case_types)]
|
||||
impl<L> EntryCustom<L> {
|
||||
impl Entry {
|
||||
pub fn fp_v1_1(&self) -> &vk::EntryFnV1_1 {
|
||||
&self.entry_fn_1_1
|
||||
}
|
||||
|
@ -175,29 +271,19 @@ impl<L> EntryCustom<L> {
|
|||
|
||||
/// Vulkan core 1.2
|
||||
#[allow(non_camel_case_types)]
|
||||
impl<L> EntryCustom<L> {
|
||||
impl Entry {
|
||||
pub fn fp_v1_2(&self) -> &vk::EntryFnV1_2 {
|
||||
&self.entry_fn_1_2
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum InstanceError {
|
||||
LoadError(Vec<&'static str>),
|
||||
VkError(vk::Result),
|
||||
}
|
||||
|
||||
impl fmt::Display for InstanceError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
InstanceError::LoadError(e) => write!(f, "{}", e.join("; ")),
|
||||
InstanceError::VkError(e) => write!(f, "{}", e),
|
||||
}
|
||||
#[cfg(feature = "linked")]
|
||||
impl Default for Entry {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for InstanceError {}
|
||||
|
||||
impl vk::StaticFn {
|
||||
pub fn load_checked<F>(mut _f: F) -> Result<Self, MissingEntryPoint>
|
||||
where
|
||||
|
@ -228,3 +314,50 @@ impl std::fmt::Display for MissingEntryPoint {
|
|||
}
|
||||
}
|
||||
impl std::error::Error for MissingEntryPoint {}
|
||||
|
||||
#[cfg(feature = "linked")]
|
||||
extern "system" {
|
||||
fn vkGetInstanceProcAddr(instance: vk::Instance, name: *const c_char)
|
||||
-> vk::PFN_vkVoidFunction;
|
||||
}
|
||||
|
||||
#[cfg(feature = "loaded")]
|
||||
mod loaded {
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
|
||||
pub enum LoadingError {
|
||||
LibraryLoadFailure(libloading::Error),
|
||||
MissingEntryPoint(MissingEntryPoint),
|
||||
}
|
||||
|
||||
impl fmt::Display for LoadingError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
LoadingError::LibraryLoadFailure(err) => fmt::Display::fmt(err, f),
|
||||
LoadingError::MissingEntryPoint(err) => fmt::Display::fmt(err, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for LoadingError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(match self {
|
||||
LoadingError::LibraryLoadFailure(err) => err,
|
||||
LoadingError::MissingEntryPoint(err) => err,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MissingEntryPoint> for LoadingError {
|
||||
fn from(err: MissingEntryPoint) -> Self {
|
||||
LoadingError::MissingEntryPoint(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "loaded")]
|
||||
pub use self::loaded::*;
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
use crate::entry::EntryCustom;
|
||||
use crate::entry::MissingEntryPoint;
|
||||
use libloading::Library;
|
||||
use std::error::Error;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(windows)]
|
||||
const LIB_PATH: &str = "vulkan-1.dll";
|
||||
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "macos", target_os = "ios", target_os = "android"))
|
||||
))]
|
||||
const LIB_PATH: &str = "libvulkan.so.1";
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
const LIB_PATH: &str = "libvulkan.so";
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
const LIB_PATH: &str = "libvulkan.dylib";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoadingError {
|
||||
LibraryLoadFailure(libloading::Error),
|
||||
MissingEntryPoint(MissingEntryPoint),
|
||||
}
|
||||
|
||||
impl fmt::Display for LoadingError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
LoadingError::LibraryLoadFailure(err) => fmt::Display::fmt(err, f),
|
||||
LoadingError::MissingEntryPoint(err) => fmt::Display::fmt(err, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for LoadingError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(match self {
|
||||
LoadingError::LibraryLoadFailure(err) => err,
|
||||
LoadingError::MissingEntryPoint(err) => err,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MissingEntryPoint> for LoadingError {
|
||||
fn from(err: MissingEntryPoint) -> Self {
|
||||
LoadingError::MissingEntryPoint(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Default function loader
|
||||
pub type Entry = EntryCustom<Arc<Library>>;
|
||||
|
||||
impl Entry {
|
||||
/// Load default Vulkan library for the current platform
|
||||
///
|
||||
/// # Safety
|
||||
/// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
|
||||
/// for [`Library::new`] and [`Library::get`] apply here.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use ash::{vk, Entry};
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let entry = unsafe { Entry::new() }?;
|
||||
/// let app_info = vk::ApplicationInfo {
|
||||
/// api_version: vk::make_api_version(0, 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 unsafe fn new() -> Result<Entry, LoadingError> {
|
||||
Self::with_library(LIB_PATH)
|
||||
}
|
||||
|
||||
/// Load Vulkan library at `path`
|
||||
///
|
||||
/// # Safety
|
||||
/// `dlopen`ing native libraries is inherently unsafe. The safety guidelines
|
||||
/// for [`Library::new`] and [`Library::get`] apply here.
|
||||
pub unsafe fn with_library(path: impl AsRef<OsStr>) -> Result<Entry, LoadingError> {
|
||||
let lib = Library::new(path)
|
||||
.map_err(LoadingError::LibraryLoadFailure)
|
||||
.map(Arc::new)?;
|
||||
|
||||
Ok(Self::new_custom(lib, |vk_lib, name| {
|
||||
vk_lib
|
||||
.get(name.to_bytes_with_nul())
|
||||
.map(|symbol| *symbol)
|
||||
.unwrap_or(ptr::null_mut())
|
||||
})?)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct DebugReport {
|
|||
}
|
||||
|
||||
impl DebugReport {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let debug_report_fn = vk::ExtDebugReportFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{vk, RawPtr};
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -11,7 +11,7 @@ pub struct DebugUtils {
|
|||
}
|
||||
|
||||
impl DebugUtils {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let debug_utils_fn = vk::ExtDebugUtilsFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct MetalSurface {
|
|||
}
|
||||
|
||||
impl MetalSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::ExtMetalSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -11,7 +11,7 @@ pub struct ToolingInfo {
|
|||
}
|
||||
|
||||
impl ToolingInfo {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let tooling_info_fn = vk::ExtToolingInfoFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct AndroidSurface {
|
|||
}
|
||||
|
||||
impl AndroidSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::KhrAndroidSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct Display {
|
|||
}
|
||||
|
||||
impl Display {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let display_fn = vk::KhrDisplayFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
@ -12,7 +12,7 @@ pub struct GetPhysicalDeviceProperties2 {
|
|||
}
|
||||
|
||||
impl GetPhysicalDeviceProperties2 {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let get_physical_device_properties2_fn =
|
||||
vk::KhrGetPhysicalDeviceProperties2Fn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -11,7 +11,7 @@ pub struct PipelineExecutableProperties {
|
|||
}
|
||||
|
||||
impl PipelineExecutableProperties {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let pipeline_executable_properties_fn =
|
||||
vk::KhrPipelineExecutablePropertiesFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct Surface {
|
|||
}
|
||||
|
||||
impl Surface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::KhrSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -11,7 +11,7 @@ pub struct TimelineSemaphore {
|
|||
}
|
||||
|
||||
impl TimelineSemaphore {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let timeline_semaphore_fn = vk::KhrTimelineSemaphoreFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct WaylandSurface {
|
|||
}
|
||||
|
||||
impl WaylandSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::KhrWaylandSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct Win32Surface {
|
|||
}
|
||||
|
||||
impl Win32Surface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::KhrWin32SurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct XcbSurface {
|
|||
}
|
||||
|
||||
impl XcbSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::KhrXcbSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct XlibSurface {
|
|||
}
|
||||
|
||||
impl XlibSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::KhrXlibSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct IOSSurface {
|
|||
}
|
||||
|
||||
impl IOSSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::MvkIosSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct MacOSSurface {
|
|||
}
|
||||
|
||||
impl MacOSSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::MvkMacosSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::prelude::*;
|
||||
use crate::vk;
|
||||
use crate::RawPtr;
|
||||
use crate::{EntryCustom, Instance};
|
||||
use crate::{Entry, Instance};
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct ViSurface {
|
|||
}
|
||||
|
||||
impl ViSurface {
|
||||
pub fn new<L>(entry: &EntryCustom<L>, instance: &Instance) -> Self {
|
||||
pub fn new(entry: &Entry, instance: &Instance) -> Self {
|
||||
let surface_fn = vk::NnViSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
clippy::missing_safety_doc,
|
||||
clippy::upper_case_acronyms
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
//! # Vulkan API
|
||||
//!
|
||||
//! <https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/index.html>
|
||||
|
@ -12,7 +13,7 @@
|
|||
//! ```no_run
|
||||
//! use ash::{vk, Entry};
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let entry = unsafe { Entry::new() }?;
|
||||
//! let entry = Entry::new();
|
||||
//! let app_info = vk::ApplicationInfo {
|
||||
//! api_version: vk::make_api_version(0, 1, 0, 0),
|
||||
//! ..Default::default()
|
||||
|
@ -26,22 +27,19 @@
|
|||
//! ```
|
||||
//!
|
||||
//! ## Getting started
|
||||
//! Load the Vulkan library at the default location using [`Entry::new()`][EntryCustom<_>::new()],
|
||||
//! or at a custom location using [`Entry::with_library("path/to/vulkan")`][EntryCustom<_>::with_library()].
|
||||
//! These loaders use [`libloading`]. If you wish to perform function loading yourself
|
||||
//! call [`EntryCustom::new_custom()`] with a closure turning function names
|
||||
//! into function pointers.
|
||||
//!
|
||||
//! Load the Vulkan library linked at compile time using [`Entry::new()`], or load it at runtime
|
||||
//! using [`Entry::load()`], which uses `libloading`. If you want to perform entry point loading
|
||||
//! yourself, call [`Entry::from_static_fn()`].
|
||||
|
||||
pub use crate::device::Device;
|
||||
pub use crate::entry::{EntryCustom, InstanceError};
|
||||
#[cfg(feature = "libloading")]
|
||||
pub use crate::entry_libloading::{Entry, LoadingError};
|
||||
pub use crate::entry::Entry;
|
||||
#[cfg(feature = "loaded")]
|
||||
pub use crate::entry::LoadingError;
|
||||
pub use crate::instance::Instance;
|
||||
|
||||
mod device;
|
||||
mod entry;
|
||||
#[cfg(feature = "libloading")]
|
||||
mod entry_libloading;
|
||||
mod instance;
|
||||
pub mod prelude;
|
||||
pub mod util;
|
||||
|
|
|
@ -7,7 +7,7 @@ use ash::extensions::{
|
|||
};
|
||||
|
||||
use ash::{vk, Entry};
|
||||
pub use ash::{Device, EntryCustom, Instance};
|
||||
pub use ash::{Device, Instance};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::default::Default;
|
||||
|
@ -204,7 +204,7 @@ impl ExampleBase {
|
|||
))
|
||||
.build(&events_loop)
|
||||
.unwrap();
|
||||
let entry = Entry::new().unwrap();
|
||||
let entry = Entry::new();
|
||||
let app_name = CString::new("VulkanTriangle").unwrap();
|
||||
|
||||
let layer_names = [CString::new("VK_LAYER_KHRONOS_validation").unwrap()];
|
||||
|
|
Loading…
Reference in a new issue