aboutsummaryrefslogtreecommitdiff
path: root/src/instance
diff options
context:
space:
mode:
Diffstat (limited to 'src/instance')
-rw-r--r--src/instance/debug.rs755
-rw-r--r--src/instance/extensions.rs153
-rw-r--r--src/instance/instance.rs693
-rw-r--r--src/instance/layers.rs194
-rw-r--r--src/instance/loader.rs316
-rw-r--r--src/instance/mod.rs880
6 files changed, 1321 insertions, 1670 deletions
diff --git a/src/instance/debug.rs b/src/instance/debug.rs
index 2bc0615..7e5a75e 100644
--- a/src/instance/debug.rs
+++ b/src/instance/debug.rs
@@ -7,9 +7,9 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-//! Debug callback called by intermediate layers or by the driver.
+//! Debug messenger called by intermediate layers or by the driver.
//!
-//! When working on an application, it is recommended to register a debug callback. For example if
+//! When working on an application, it is recommended to register a debug messenger. For example if
//! you enable the validation layers provided by the official Vulkan SDK, they will warn you about
//! invalid API usages or performance problems by calling this callback. The callback can also
//! be called by the driver or by whatever intermediate layer is activated.
@@ -17,445 +17,528 @@
//! Note that the vulkano library can also emit messages to warn you about performance issues.
//! TODO: ^ that's not the case yet, need to choose whether we keep this idea
//!
-//! # Example
+//! # Examples
//!
//! ```
//! # use vulkano::instance::Instance;
//! # use std::sync::Arc;
//! # let instance: Arc<Instance> = return;
-//! use vulkano::instance::debug::DebugCallback;
+//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo};
//!
-//! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
-//! println!("Debug callback: {:?}", msg.description);
-//! }).ok();
+//! let _callback = unsafe {
+//! DebugUtilsMessenger::new(
+//! instance,
+//! DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| {
+//! println!("Debug callback: {:?}", msg.description);
+//! })),
+//! ).ok()
+//! };
//! ```
//!
-//! The type of `msg` in the callback is [`Message`](struct.Message.html).
+//! The type of `msg` in the callback is [`Message`].
//!
//! Note that you must keep the `_callback` object alive for as long as you want your callback to
-//! be callable. If you don't store the return value of `DebugCallback`'s constructor in a
+//! be callable. If you don't store the return value of `DebugUtilsMessenger`'s constructor in a
//! variable, it will be immediately destroyed and your callback will not work.
-//!
-use crate::check_errors;
-use crate::instance::Instance;
-use crate::Error;
-use crate::VulkanObject;
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::os::raw::c_void;
-use std::panic;
-use std::ptr;
-use std::sync::Arc;
+use super::Instance;
+use crate::{
+ macros::{vulkan_bitflags, vulkan_enum},
+ RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ ffi::{c_void, CStr},
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ panic::{catch_unwind, AssertUnwindSafe, RefUnwindSafe},
+ ptr,
+ sync::Arc,
+};
+
+pub(super) type UserCallback = Arc<dyn Fn(&Message<'_>) + RefUnwindSafe + Send + Sync>;
/// Registration of a callback called by validation layers.
///
/// The callback can be called as long as this object is alive.
-#[must_use = "The DebugCallback object must be kept alive for as long as you want your callback \
- to be called"]
-pub struct DebugCallback {
+#[must_use = "The DebugUtilsMessenger object must be kept alive for as long as you want your callback to be called"]
+pub struct DebugUtilsMessenger {
+ handle: ash::vk::DebugUtilsMessengerEXT,
instance: Arc<Instance>,
- debug_report_callback: ash::vk::DebugUtilsMessengerEXT,
- user_callback: Box<Box<dyn Fn(&Message) + Send>>,
+ _user_callback: Box<UserCallback>,
}
-impl DebugCallback {
+impl DebugUtilsMessenger {
/// Initializes a debug callback.
///
- /// Panics generated by calling `user_callback` are ignored.
- pub fn new<F>(
- instance: &Arc<Instance>,
- severity: MessageSeverity,
- ty: MessageType,
- user_callback: F,
- ) -> Result<DebugCallback, DebugCallbackCreationError>
- where
- F: Fn(&Message) + 'static + Send + panic::RefUnwindSafe,
- {
+ /// # Panics
+ ///
+ /// - Panics if the `message_severity` or `message_type` members of `create_info` are empty.
+ ///
+ /// # Safety
+ ///
+ /// - `create_info.user_callback` must not make any calls to the Vulkan API.
+ pub unsafe fn new(
+ instance: Arc<Instance>,
+ mut create_info: DebugUtilsMessengerCreateInfo,
+ ) -> Result<Self, DebugUtilsMessengerCreationError> {
+ Self::validate_create(&instance, &mut create_info)?;
+ let (handle, user_callback) = Self::record_create(&instance, create_info)?;
+
+ Ok(DebugUtilsMessenger {
+ handle,
+ instance,
+ _user_callback: user_callback,
+ })
+ }
+
+ fn validate_create(
+ instance: &Instance,
+ create_info: &mut DebugUtilsMessengerCreateInfo,
+ ) -> Result<(), DebugUtilsMessengerCreationError> {
+ let &mut DebugUtilsMessengerCreateInfo {
+ message_type,
+ message_severity,
+ user_callback: _,
+ _ne: _,
+ } = create_info;
+
if !instance.enabled_extensions().ext_debug_utils {
- return Err(DebugCallbackCreationError::MissingExtension);
+ return Err(DebugUtilsMessengerCreationError::RequirementNotMet {
+ required_for: "`DebugUtilsMessenger::new`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
}
- // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
- // that can't be cast to a `*const c_void`.
- let user_callback = Box::new(Box::new(user_callback) as Box<_>);
-
- unsafe extern "system" fn callback(
- severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT,
- ty: ash::vk::DebugUtilsMessageTypeFlagsEXT,
- callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT,
- user_data: *mut c_void,
- ) -> ash::vk::Bool32 {
- let user_callback = user_data as *mut Box<dyn Fn()> as *const _;
- let user_callback: &Box<dyn Fn(&Message)> = &*user_callback;
-
- let layer_prefix = (*callback_data)
- .p_message_id_name
- .as_ref()
- .map(|msg_id_name| {
- CStr::from_ptr(msg_id_name)
- .to_str()
- .expect("debug callback message not utf-8")
- });
-
- let description = CStr::from_ptr((*callback_data).p_message)
- .to_str()
- .expect("debug callback message not utf-8");
-
- let message = Message {
- severity: MessageSeverity {
- information: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO)
- .is_empty(),
- warning: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING)
- .is_empty(),
- error: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR)
- .is_empty(),
- verbose: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE)
- .is_empty(),
- },
- ty: MessageType {
- general: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL).is_empty(),
- validation: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION)
- .is_empty(),
- performance: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE)
- .is_empty(),
- },
- layer_prefix,
- description,
- };
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
+ message_severity.validate_instance(instance)?;
- // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
- // bound is enforced. Therefore we enforce it manually.
- let _ = panic::catch_unwind(panic::AssertUnwindSafe(move || {
- user_callback(&message);
- }));
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
+ assert!(!message_severity.is_empty());
- ash::vk::FALSE
- }
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
+ message_type.validate_instance(instance)?;
- let severity = {
- let mut flags = ash::vk::DebugUtilsMessageSeverityFlagsEXT::empty();
- if severity.information {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
- }
- if severity.warning {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
- }
- if severity.error {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
- }
- if severity.verbose {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
- }
- flags
- };
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
+ assert!(!message_type.is_empty());
- let ty = {
- let mut flags = ash::vk::DebugUtilsMessageTypeFlagsEXT::empty();
- if ty.general {
- flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL;
- }
- if ty.validation {
- flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION;
- }
- if ty.performance {
- flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
- }
- flags
- };
+ // VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
+ // Can't be checked, creation is unsafe.
+
+ Ok(())
+ }
+
+ unsafe fn record_create(
+ instance: &Instance,
+ create_info: DebugUtilsMessengerCreateInfo,
+ ) -> Result<
+ (ash::vk::DebugUtilsMessengerEXT, Box<UserCallback>),
+ DebugUtilsMessengerCreationError,
+ > {
+ let DebugUtilsMessengerCreateInfo {
+ message_severity,
+ message_type,
+ user_callback,
+ _ne: _,
+ } = create_info;
+
+ // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
+ // that can't be cast to a `*const c_void`.
+ let user_callback = Box::new(user_callback);
- let infos = ash::vk::DebugUtilsMessengerCreateInfoEXT {
+ let create_info = ash::vk::DebugUtilsMessengerCreateInfoEXT {
flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
- message_severity: severity,
- message_type: ty,
- pfn_user_callback: Some(callback),
- p_user_data: &*user_callback as &Box<_> as *const Box<_> as *const c_void as *mut _,
+ message_severity: message_severity.into(),
+ message_type: message_type.into(),
+ pfn_user_callback: Some(trampoline),
+ p_user_data: &*user_callback as &Arc<_> as *const Arc<_> as *const c_void as *mut _,
..Default::default()
};
let fns = instance.fns();
- let debug_report_callback = unsafe {
+ let handle = {
let mut output = MaybeUninit::uninit();
- check_errors(fns.ext_debug_utils.create_debug_utils_messenger_ext(
- instance.internal_object(),
- &infos,
+ (fns.ext_debug_utils.create_debug_utils_messenger_ext)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(DebugCallback {
- instance: instance.clone(),
- debug_report_callback,
- user_callback,
- })
- }
-
- /// Initializes a debug callback with errors and warnings.
- ///
- /// Shortcut for `new(instance, MessageTypes::errors_and_warnings(), user_callback)`.
- #[inline]
- pub fn errors_and_warnings<F>(
- instance: &Arc<Instance>,
- user_callback: F,
- ) -> Result<DebugCallback, DebugCallbackCreationError>
- where
- F: Fn(&Message) + Send + 'static + panic::RefUnwindSafe,
- {
- DebugCallback::new(
- instance,
- MessageSeverity::errors_and_warnings(),
- MessageType::general(),
- user_callback,
- )
+ Ok((handle, user_callback))
}
}
-impl Drop for DebugCallback {
+impl Drop for DebugUtilsMessenger {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.instance.fns();
- fns.ext_debug_utils.destroy_debug_utils_messenger_ext(
- self.instance.internal_object(),
- self.debug_report_callback,
+ (fns.ext_debug_utils.destroy_debug_utils_messenger_ext)(
+ self.instance.handle(),
+ self.handle,
ptr::null(),
);
}
}
}
-/// A message received by the callback.
-pub struct Message<'a> {
- /// Severity of message.
- pub severity: MessageSeverity,
- /// Type of message,
- pub ty: MessageType,
- /// Prefix of the layer that reported this message or `None` if unknown.
- pub layer_prefix: Option<&'a str>,
- /// Description of the message.
- pub description: &'a str,
+impl Debug for DebugUtilsMessenger {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ handle,
+ instance,
+ _user_callback: _,
+ } = self;
+
+ f.debug_struct("DebugUtilsMessenger")
+ .field("handle", handle)
+ .field("instance", instance)
+ .finish_non_exhaustive()
+ }
}
-/// Severity of message.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct MessageSeverity {
- /// An error that may cause undefined results, including an application crash.
- pub error: bool,
- /// An unexpected use.
- pub warning: bool,
- /// An informational message that may be handy when debugging an application.
- pub information: bool,
- /// Diagnostic information from the loader and layers.
- pub verbose: bool,
+pub(super) unsafe extern "system" fn trampoline(
+ message_severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT,
+ message_types: ash::vk::DebugUtilsMessageTypeFlagsEXT,
+ callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT,
+ user_data: *mut c_void,
+) -> ash::vk::Bool32 {
+ // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
+ // bound is enforced. Therefore we enforce it manually.
+ let _ = catch_unwind(AssertUnwindSafe(move || {
+ let user_callback = user_data as *mut UserCallback as *const _;
+ let user_callback: &UserCallback = &*user_callback;
+
+ let layer_prefix = (*callback_data)
+ .p_message_id_name
+ .as_ref()
+ .map(|msg_id_name| {
+ CStr::from_ptr(msg_id_name)
+ .to_str()
+ .expect("debug callback message not utf-8")
+ });
+
+ let description = CStr::from_ptr((*callback_data).p_message)
+ .to_str()
+ .expect("debug callback message not utf-8");
+
+ let message = Message {
+ severity: message_severity.into(),
+ ty: message_types.into(),
+ layer_prefix,
+ description,
+ };
+
+ user_callback(&message);
+ }));
+
+ ash::vk::FALSE
}
-impl MessageSeverity {
- /// Builds a `MessageSeverity` with all fields set to `false` expect `error`.
- #[inline]
- pub const fn errors() -> MessageSeverity {
- MessageSeverity {
- error: true,
- ..MessageSeverity::none()
- }
- }
+/// Error that can happen when creating a `DebugUtilsMessenger`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum DebugUtilsMessengerCreationError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `warning`.
- #[inline]
- pub const fn warnings() -> MessageSeverity {
- MessageSeverity {
- warning: true,
- ..MessageSeverity::none()
+impl Error for DebugUtilsMessengerCreationError {}
+
+impl Display for DebugUtilsMessengerCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
}
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `information`.
- #[inline]
- pub const fn information() -> MessageSeverity {
- MessageSeverity {
- information: true,
- ..MessageSeverity::none()
- }
+impl From<VulkanError> for DebugUtilsMessengerCreationError {
+ fn from(err: VulkanError) -> DebugUtilsMessengerCreationError {
+ panic!("unexpected error: {:?}", err)
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `verbose`.
- #[inline]
- pub const fn verbose() -> MessageSeverity {
- MessageSeverity {
- verbose: true,
- ..MessageSeverity::none()
+impl From<RequirementNotMet> for DebugUtilsMessengerCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
}
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `error`, `warning`
- /// and `performance_warning`.
- #[inline]
- pub const fn errors_and_warnings() -> MessageSeverity {
- MessageSeverity {
- error: true,
- warning: true,
- ..MessageSeverity::none()
- }
- }
+/// Parameters to create a `DebugUtilsMessenger`.
+#[derive(Clone)]
+pub struct DebugUtilsMessengerCreateInfo {
+ /// The message severity types that the callback should be called for.
+ ///
+ /// The value must not be empty.
+ ///
+ /// The default value is `MessageSeverity::errors_and_warnings()`.
+ pub message_severity: DebugUtilsMessageSeverity,
- /// Builds a `MessageSeverity` with all fields set to `false`.
- #[inline]
- pub const fn none() -> MessageSeverity {
- MessageSeverity {
- error: false,
- warning: false,
- information: false,
- verbose: false,
- }
- }
+ /// The message types that the callback should be called for.
+ ///
+ /// The value must not be empty.
+ ///
+ /// The default value is `MessageType::general()`.
+ pub message_type: DebugUtilsMessageType,
+
+ /// The closure that should be called.
+ ///
+ /// The closure must not make any calls to the Vulkan API.
+ /// If the closure panics, the panic is caught and ignored.
+ ///
+ /// The callback is provided inside an `Arc` so that it can be shared across multiple
+ /// messengers.
+ pub user_callback: UserCallback,
- /// Builds a `MessageSeverity` with all fields set to `true`.
+ pub _ne: crate::NonExhaustive,
+}
+
+impl DebugUtilsMessengerCreateInfo {
+ /// Returns a `DebugUtilsMessengerCreateInfo` with the specified `user_callback`.
#[inline]
- pub const fn all() -> MessageSeverity {
- MessageSeverity {
- error: true,
- warning: true,
- information: true,
- verbose: true,
+ pub fn user_callback(user_callback: UserCallback) -> Self {
+ Self {
+ message_severity: DebugUtilsMessageSeverity::ERROR | DebugUtilsMessageSeverity::WARNING,
+ message_type: DebugUtilsMessageType::GENERAL,
+ user_callback,
+ _ne: crate::NonExhaustive(()),
}
}
}
-impl std::ops::BitOr for MessageSeverity {
- type Output = Self;
- fn bitor(self, rhs: Self) -> Self::Output {
- MessageSeverity {
- error: self.error | rhs.error,
- warning: self.warning | rhs.warning,
- information: self.information | rhs.information,
- verbose: self.verbose | rhs.verbose,
- }
+impl Debug for DebugUtilsMessengerCreateInfo {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ message_severity,
+ message_type,
+ user_callback: _,
+ _ne: _,
+ } = self;
+
+ f.debug_struct("DebugUtilsMessengerCreateInfo")
+ .field("message_severity", message_severity)
+ .field("message_type", message_type)
+ .finish_non_exhaustive()
}
}
-/// Type of message.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct MessageType {
+/// A message received by the callback.
+pub struct Message<'a> {
+ /// Severity of message.
+ pub severity: DebugUtilsMessageSeverity,
+ /// Type of message,
+ pub ty: DebugUtilsMessageType,
+ /// Prefix of the layer that reported this message or `None` if unknown.
+ pub layer_prefix: Option<&'a str>,
+ /// Description of the message.
+ pub description: &'a str,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Severity of message.
+ DebugUtilsMessageSeverity = DebugUtilsMessageSeverityFlagsEXT(u32);
+
+ /// An error that may cause undefined results, including an application crash.
+ ERROR = ERROR,
+
+ /// An unexpected use.
+ WARNING = WARNING,
+
+ /// An informational message that may be handy when debugging an application.
+ INFO = INFO,
+
+ /// Diagnostic information from the loader and layers.
+ VERBOSE = VERBOSE,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Type of message.
+ DebugUtilsMessageType = DebugUtilsMessageTypeFlagsEXT(u32);
+
/// Specifies that some general event has occurred.
- pub general: bool,
+ GENERAL = GENERAL,
+
/// Specifies that something has occurred during validation against the vulkan specification
- pub validation: bool,
+ VALIDATION = VALIDATION,
+
/// Specifies a potentially non-optimal use of Vulkan
- pub performance: bool,
+ PERFORMANCE = PERFORMANCE,
}
-impl MessageType {
- /// Builds a `MessageType` with general field set to `true`.
- #[inline]
- pub const fn general() -> MessageType {
- MessageType {
- general: true,
- validation: false,
- performance: false,
- }
- }
-
- /// Builds a `MessageType` with validation field set to `true`.
- #[inline]
- pub const fn validation() -> MessageType {
- MessageType {
- general: false,
- validation: true,
- performance: false,
- }
- }
+/// A label to associate with a span of work in a queue.
+///
+/// When debugging, labels can be useful to identify which queue, or where in a specific queue,
+/// something happened.
+#[derive(Clone, Debug)]
+pub struct DebugUtilsLabel {
+ /// The name of the label.
+ ///
+ /// The default value is empty.
+ pub label_name: String,
- /// Builds a `MessageType` with performance field set to `true`.
- #[inline]
- pub const fn performance() -> MessageType {
- MessageType {
- general: false,
- validation: false,
- performance: true,
- }
- }
+ /// An RGBA color value that is associated with the label, with values in the range `0.0..=1.0`.
+ ///
+ /// If set to `[0.0; 4]`, the value is ignored.
+ ///
+ /// The default value is `[0.0; 4]`.
+ pub color: [f32; 4],
- /// Builds a `MessageType` with all fields set to `true`.
- #[inline]
- pub const fn all() -> MessageType {
- MessageType {
- general: true,
- validation: true,
- performance: true,
- }
- }
+ pub _ne: crate::NonExhaustive,
+}
- /// Builds a `MessageType` with all fields set to `false`.
+impl Default for DebugUtilsLabel {
#[inline]
- pub const fn none() -> MessageType {
- MessageType {
- general: false,
- validation: false,
- performance: false,
+ fn default() -> Self {
+ Self {
+ label_name: String::new(),
+ color: [0.0; 4],
+ _ne: crate::NonExhaustive(()),
}
}
}
-impl std::ops::BitOr for MessageType {
- type Output = Self;
- fn bitor(self, rhs: Self) -> Self::Output {
- MessageType {
- general: self.general | rhs.general,
- validation: self.validation | rhs.validation,
- performance: self.performance | rhs.performance,
- }
- }
-}
+vulkan_enum! {
+ #[non_exhaustive]
-/// Error that can happen when creating a debug callback.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum DebugCallbackCreationError {
- /// The `EXT_debug_utils` extension was not enabled.
- MissingExtension,
-}
+ /// Features of the validation layer to enable.
+ ValidationFeatureEnable = ValidationFeatureEnableEXT(i32);
-impl error::Error for DebugCallbackCreationError {}
+ /// The validation layer will use shader programs running on the GPU to provide additional
+ /// validation.
+ ///
+ /// This must not be used together with `DebugPrintf`.
+ GpuAssisted = GPU_ASSISTED,
-impl fmt::Display for DebugCallbackCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- DebugCallbackCreationError::MissingExtension => {
- "the `EXT_debug_utils` extension was not enabled"
- }
- }
- )
- }
+ /// The validation layer will reserve and use one descriptor set slot for its own use.
+ /// The limit reported by
+ /// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets)
+ /// will be reduced by 1.
+ ///
+ /// `GpuAssisted` must also be enabled.
+ GpuAssistedReserveBindingSlot = GPU_ASSISTED_RESERVE_BINDING_SLOT,
+
+ /// The validation layer will report recommendations that are not strictly errors,
+ /// but that may be considered good Vulkan practice.
+ BestPractices = BEST_PRACTICES,
+
+ /// The validation layer will process `debugPrintfEXT` operations in shaders, and send them
+ /// to the debug callback.
+ ///
+ /// This must not be used together with `GpuAssisted`.
+ DebugPrintf = DEBUG_PRINTF,
+
+ /// The validation layer will report errors relating to synchronization, such as data races and
+ /// the use of synchronization primitives.
+ SynchronizationValidation = SYNCHRONIZATION_VALIDATION,
}
-impl From<Error> for DebugCallbackCreationError {
- #[inline]
- fn from(err: Error) -> DebugCallbackCreationError {
- panic!("unexpected error: {:?}", err)
- }
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Features of the validation layer to disable.
+ ValidationFeatureDisable = ValidationFeatureDisableEXT(i32);
+
+ /// All validation is disabled.
+ All = ALL,
+
+ /// Shader validation is disabled.
+ Shaders = SHADERS,
+
+ /// Thread safety validation is disabled.
+ ThreadSafety = THREAD_SAFETY,
+
+ /// Stateless parameter validation is disabled.
+ ApiParameters = API_PARAMETERS,
+
+ /// Object lifetime validation is disabled.
+ ObjectLifetimes = OBJECT_LIFETIMES,
+
+ /// Core validation checks are disabled.
+ ///
+ /// This also disables shader validation and GPU-assisted validation.
+ CoreChecks = CORE_CHECKS,
+
+ /// Protection against duplicate non-dispatchable handles is disabled.
+ UniqueHandles = UNIQUE_HANDLES,
+
+ /// Results of shader validation will not be cached, and are validated from scratch each time.
+ ShaderValidationCache = SHADER_VALIDATION_CACHE,
}
#[cfg(test)]
mod tests {
use super::*;
+ use crate::{
+ instance::{InstanceCreateInfo, InstanceExtensions},
+ VulkanLibrary,
+ };
use std::thread;
+
#[test]
fn ensure_sendable() {
- // It's useful to be able to initialize a DebugCallback on one thread
+ // It's useful to be able to initialize a DebugUtilsMessenger on one thread
// and keep it alive on another thread.
- let instance = instance!();
- let severity = MessageSeverity::none();
- let ty = MessageType::all();
- let callback = DebugCallback::new(&instance, severity, ty, |_| {});
+ let instance = {
+ let library = match VulkanLibrary::new() {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ match Instance::new(
+ library,
+ InstanceCreateInfo {
+ enabled_extensions: InstanceExtensions {
+ ext_debug_utils: true,
+ ..InstanceExtensions::empty()
+ },
+ ..Default::default()
+ },
+ ) {
+ Ok(x) => x,
+ Err(_) => return,
+ }
+ };
+
+ let callback = unsafe {
+ DebugUtilsMessenger::new(
+ instance,
+ DebugUtilsMessengerCreateInfo {
+ message_severity: DebugUtilsMessageSeverity::ERROR,
+ message_type: DebugUtilsMessageType::GENERAL
+ | DebugUtilsMessageType::VALIDATION
+ | DebugUtilsMessageType::PERFORMANCE,
+ ..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|_| {}))
+ },
+ )
+ }
+ .unwrap();
thread::spawn(move || {
- let _ = callback;
+ drop(callback);
});
}
}
diff --git a/src/instance/extensions.rs b/src/instance/extensions.rs
index dab0b12..3aac844 100644
--- a/src/instance/extensions.rs
+++ b/src/instance/extensions.rs
@@ -7,138 +7,10 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-pub use crate::extensions::{
- ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
-};
-use crate::instance::loader;
-use crate::instance::loader::LoadingError;
-use std::ffi::CStr;
-use std::ptr;
+pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError};
-macro_rules! instance_extensions {
- (
- $($member:ident => {
- doc: $doc:expr,
- raw: $raw:expr,
- requires_core: $requires_core:expr,
- requires_instance_extensions: [$($requires_instance_extension:ident),*]$(,)?
- },)*
- ) => (
- extensions! {
- InstanceExtensions,
- $($member => {
- doc: $doc,
- raw: $raw,
- requires_core: $requires_core,
- requires_device_extensions: [],
- requires_instance_extensions: [$($requires_instance_extension),*],
- },)*
- }
-
- impl InstanceExtensions {
- /// Checks enabled extensions against the instance version and each other.
- pub(super) fn check_requirements(
- &self,
- supported: &InstanceExtensions,
- api_version: crate::Version,
- ) -> Result<(), crate::extensions::ExtensionRestrictionError> {
- $(
- if self.$member {
- if !supported.$member {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::NotSupported,
- });
- }
-
- if api_version < $requires_core {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiresCore($requires_core),
- });
- } else {
- $(
- if !self.$requires_instance_extension {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiresInstanceExtension(stringify!($requires_instance_extension)),
- });
- }
- )*
- }
- }
- )*
- Ok(())
- }
- }
- );
-}
-
-pub use crate::autogen::InstanceExtensions;
-pub(crate) use instance_extensions;
-
-impl InstanceExtensions {
- /// See the docs of supported_by_core().
- pub fn supported_by_core_raw() -> Result<Self, SupportedExtensionsError> {
- InstanceExtensions::supported_by_core_raw_with_loader(loader::auto_loader()?)
- }
-
- /// Returns an `InstanceExtensions` object with extensions supported by the core driver.
- pub fn supported_by_core() -> Result<Self, LoadingError> {
- match InstanceExtensions::supported_by_core_raw() {
- Ok(l) => Ok(l),
- Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
- Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
- }
- }
-
- /// Same as `supported_by_core`, but allows specifying a loader.
- pub fn supported_by_core_with_loader<L>(
- ptrs: &loader::FunctionPointers<L>,
- ) -> Result<Self, LoadingError>
- where
- L: loader::Loader,
- {
- match InstanceExtensions::supported_by_core_raw_with_loader(ptrs) {
- Ok(l) => Ok(l),
- Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
- Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
- }
- }
-
- /// See the docs of supported_by_core().
- pub fn supported_by_core_raw_with_loader<L>(
- ptrs: &loader::FunctionPointers<L>,
- ) -> Result<Self, SupportedExtensionsError>
- where
- L: loader::Loader,
- {
- let fns = ptrs.fns();
-
- let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
- let mut num = 0;
- check_errors(fns.v1_0.enumerate_instance_extension_properties(
- ptr::null(),
- &mut num,
- ptr::null_mut(),
- ))?;
-
- let mut properties = Vec::with_capacity(num as usize);
- check_errors(fns.v1_0.enumerate_instance_extension_properties(
- ptr::null(),
- &mut num,
- properties.as_mut_ptr(),
- ))?;
- properties.set_len(num as usize);
- properties
- };
-
- Ok(Self::from(properties.iter().map(|property| unsafe {
- CStr::from_ptr(property.extension_name.as_ptr())
- })))
- }
-}
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/instance_extensions.rs"));
#[cfg(test)]
mod tests {
@@ -147,7 +19,22 @@ mod tests {
#[test]
fn empty_extensions() {
- let i: Vec<CString> = (&InstanceExtensions::none()).into();
- assert!(i.iter().next().is_none());
+ let i: Vec<CString> = (&InstanceExtensions::empty()).into();
+ assert!(i.get(0).is_none());
+ }
+
+ #[test]
+ fn into_iter() {
+ let extensions = InstanceExtensions {
+ khr_display: true,
+ ..InstanceExtensions::empty()
+ };
+ for (name, enabled) in extensions {
+ if name == "VK_KHR_display" {
+ assert!(enabled);
+ } else {
+ assert!(!enabled);
+ }
+ }
}
}
diff --git a/src/instance/instance.rs b/src/instance/instance.rs
deleted file mode 100644
index 50712d2..0000000
--- a/src/instance/instance.rs
+++ /dev/null
@@ -1,693 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::device::physical::{init_physical_devices, PhysicalDeviceInfo};
-use crate::extensions::ExtensionRestrictionError;
-use crate::fns::InstanceFunctions;
-use crate::instance::loader;
-use crate::instance::loader::FunctionPointers;
-use crate::instance::loader::Loader;
-use crate::instance::loader::LoadingError;
-use crate::instance::InstanceExtensions;
-use crate::Error;
-use crate::OomError;
-use crate::Version;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::convert::TryInto;
-use std::error;
-use std::ffi::CString;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::mem::MaybeUninit;
-use std::ops::Deref;
-use std::ptr;
-use std::slice;
-use std::sync::Arc;
-
-/// An instance of a Vulkan context. This is the main object that should be created by an
-/// application before everything else.
-///
-/// # Application info
-///
-/// When you create an instance, you have the possibility to pass an `ApplicationInfo` struct as
-/// the first parameter. This struct contains various information about your application, most
-/// notably its name and engine.
-///
-/// Passing such a structure allows for example the driver to let the user configure the driver's
-/// behavior for your application alone through a control panel.
-///
-/// ```no_run
-/// # #[macro_use] extern crate vulkano;
-/// # fn main() {
-/// use vulkano::instance::{Instance, InstanceExtensions};
-/// use vulkano::Version;
-///
-/// // Builds an `ApplicationInfo` by looking at the content of the `Cargo.toml` file at
-/// // compile-time.
-/// let app_infos = app_info_from_cargo_toml!();
-///
-/// let _instance = Instance::new(Some(&app_infos), Version::V1_1, &InstanceExtensions::none(), None).unwrap();
-/// # }
-/// ```
-///
-/// # API versions
-///
-/// Both an `Instance` and a [`Device`](crate::device::Device) have a highest version of the Vulkan
-/// API that they support. This places a limit on what Vulkan functions and features are available
-/// to use when used on a particular instance or device. It is possible for the instance and the
-/// device to support different versions. The supported version for an instance can be queried
-/// before creation with
-/// [`FunctionPointers::api_version`](crate::instance::loader::FunctionPointers::api_version),
-/// while for a device it can be retrieved with
-/// [`PhysicalDevice::api_version`](crate::instance::PhysicalDevice::api_version).
-///
-/// When creating an `Instance`, you have to specify a maximum API version that you will use.
-/// This restricts the API version that is available for the instance and any devices created from
-/// it. For example, if both instance and device potentially support Vulkan 1.2, but you specify
-/// 1.1 as the maximum API version when creating the `Instance`, then you can only use Vulkan 1.1
-/// functions, even though they could theoretically support a higher version. You can think of it
-/// as a promise never to use any functionality from a higher version.
-///
-/// The maximum API version is not a _minimum_, so it is possible to set it to a higher version than
-/// what the instance or device inherently support. The final API version that you are able to use
-/// on an instance or device is the lower of the supported API version and the chosen maximum API
-/// version of the `Instance`.
-///
-/// However, due to a quirk in how the Vulkan 1.0 specification was written, if the instance only
-/// supports Vulkan 1.0, then it is not possible to specify a maximum API version higher than 1.0.
-/// Trying to create an `Instance` will return an `IncompatibleDriver` error. Consequently, it is
-/// not possible to use a higher device API version with an instance that only supports 1.0.
-///
-/// # Extensions
-///
-/// When creating an `Instance`, you must provide a list of extensions that must be enabled on the
-/// newly-created instance. Trying to enable an extension that is not supported by the system will
-/// result in an error.
-///
-/// Contrary to OpenGL, it is not possible to use the features of an extension if it was not
-/// explicitly enabled.
-///
-/// Extensions are especially important to take into account if you want to render images on the
-/// screen, as the only way to do so is to use the `VK_KHR_surface` extension. More information
-/// about this in the `swapchain` module.
-///
-/// For example, here is how we create an instance with the `VK_KHR_surface` and
-/// `VK_KHR_android_surface` extensions enabled, which will allow us to render images to an
-/// Android screen. You can compile and run this code on any system, but it is highly unlikely to
-/// succeed on anything else than an Android-running device.
-///
-/// ```no_run
-/// use vulkano::instance::Instance;
-/// use vulkano::instance::InstanceExtensions;
-/// use vulkano::Version;
-///
-/// let extensions = InstanceExtensions {
-/// khr_surface: true,
-/// khr_android_surface: true,
-/// .. InstanceExtensions::none()
-/// };
-///
-/// let instance = match Instance::new(None, Version::V1_1, &extensions, None) {
-/// Ok(i) => i,
-/// Err(err) => panic!("Couldn't build instance: {:?}", err)
-/// };
-/// ```
-///
-/// # Layers
-///
-/// When creating an `Instance`, you have the possibility to pass a list of **layers** that will
-/// be activated on the newly-created instance. The list of available layers can be retrieved by
-/// calling [the `layers_list` function](fn.layers_list.html).
-///
-/// A layer is a component that will hook and potentially modify the Vulkan function calls.
-/// For example, activating a layer could add a frames-per-second counter on the screen, or it
-/// could send information to a debugger that will debug your application.
-///
-/// > **Note**: From an application's point of view, layers "just exist". In practice, on Windows
-/// > and Linux, layers can be installed by third party installers or by package managers and can
-/// > also be activated by setting the value of the `VK_INSTANCE_LAYERS` environment variable
-/// > before starting the program. See the documentation of the official Vulkan loader for these
-/// > platforms.
-///
-/// > **Note**: In practice, the most common use of layers right now is for debugging purposes.
-/// > To do so, you are encouraged to set the `VK_INSTANCE_LAYERS` environment variable on Windows
-/// > or Linux instead of modifying the source code of your program. For example:
-/// > `export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump` on Linux if you installed the Vulkan SDK
-/// > will print the list of raw Vulkan function calls.
-///
-/// ## Example
-///
-/// ```
-/// # use std::sync::Arc;
-/// # use std::error::Error;
-/// # use vulkano::instance;
-/// # use vulkano::instance::Instance;
-/// # use vulkano::instance::InstanceExtensions;
-/// # use vulkano::Version;
-/// # fn test() -> Result<Arc<Instance>, Box<dyn Error>> {
-/// // For the sake of the example, we activate all the layers that
-/// // contain the word "foo" in their description.
-/// let layers: Vec<_> = instance::layers_list()?
-/// .filter(|l| l.description().contains("foo"))
-/// .collect();
-///
-/// let layer_names = layers.iter()
-/// .map(|l| l.name());
-///
-/// let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), layer_names)?;
-/// # Ok(instance)
-/// # }
-/// ```
-// TODO: mention that extensions must be supported by layers as well
-pub struct Instance {
- instance: ash::vk::Instance,
- //alloc: Option<Box<Alloc + Send + Sync>>,
-
- // The highest version that is supported for this instance.
- // This is the minimum of Instance::max_api_version and FunctionPointers::api_version.
- api_version: Version,
-
- // The highest allowed API version for instances and devices created from it.
- max_api_version: Version,
-
- pub(crate) physical_device_infos: Vec<PhysicalDeviceInfo>,
- fns: InstanceFunctions,
- extensions: InstanceExtensions,
- layers: SmallVec<[CString; 16]>,
- function_pointers: OwnedOrRef<FunctionPointers<Box<dyn Loader + Send + Sync>>>,
-}
-
-// TODO: fix the underlying cause instead
-impl ::std::panic::UnwindSafe for Instance {}
-impl ::std::panic::RefUnwindSafe for Instance {}
-
-impl Instance {
- /// Initializes a new instance of Vulkan.
- ///
- /// See the documentation of `Instance` or of [the `instance` module](index.html) for more
- /// details.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use vulkano::instance::Instance;
- /// use vulkano::instance::InstanceExtensions;
- /// use vulkano::Version;
- ///
- /// let instance = match Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None) {
- /// Ok(i) => i,
- /// Err(err) => panic!("Couldn't build instance: {:?}", err)
- /// };
- /// ```
- ///
- /// # Panic
- ///
- /// - Panics if the version numbers passed in `ApplicationInfo` are too large can't be
- /// converted into a Vulkan version number.
- /// - Panics if the application name or engine name contain a null character.
- // TODO: add a test for these ^
- // TODO: if no allocator is specified by the user, use Rust's allocator instead of leaving
- // the choice to Vulkan
- pub fn new<'a, L>(
- app_infos: Option<&ApplicationInfo>,
- max_api_version: Version,
- extensions: &InstanceExtensions,
- layers: L,
- ) -> Result<Arc<Instance>, InstanceCreationError>
- where
- L: IntoIterator<Item = &'a str>,
- {
- let layers = layers
- .into_iter()
- .map(|layer| CString::new(layer).unwrap())
- .collect::<SmallVec<[_; 16]>>();
-
- Instance::new_inner(
- app_infos,
- max_api_version,
- extensions,
- layers,
- OwnedOrRef::Ref(loader::auto_loader()?),
- )
- }
-
- /// Same as `new`, but allows specifying a loader where to load Vulkan from.
- pub fn with_loader<'a, L>(
- loader: FunctionPointers<Box<dyn Loader + Send + Sync>>,
- app_infos: Option<&ApplicationInfo>,
- max_api_version: Version,
- extensions: &InstanceExtensions,
- layers: L,
- ) -> Result<Arc<Instance>, InstanceCreationError>
- where
- L: IntoIterator<Item = &'a str>,
- {
- let layers = layers
- .into_iter()
- .map(|layer| CString::new(layer).unwrap())
- .collect::<SmallVec<[_; 16]>>();
-
- Instance::new_inner(
- app_infos,
- max_api_version,
- extensions,
- layers,
- OwnedOrRef::Owned(loader),
- )
- }
-
- fn new_inner(
- app_infos: Option<&ApplicationInfo>,
- max_api_version: Version,
- extensions: &InstanceExtensions,
- layers: SmallVec<[CString; 16]>,
- function_pointers: OwnedOrRef<FunctionPointers<Box<dyn Loader + Send + Sync>>>,
- ) -> Result<Arc<Instance>, InstanceCreationError> {
- let api_version = std::cmp::min(max_api_version, function_pointers.api_version()?);
-
- // Check if the extensions are correct
- extensions.check_requirements(
- &InstanceExtensions::supported_by_core_with_loader(&function_pointers)?,
- api_version,
- )?;
-
- // TODO: For now there are still buggy drivers that will segfault if you don't pass any
- // appinfos. Therefore for now we ensure that it can't be `None`.
- let def = Default::default();
- let app_infos = match app_infos {
- Some(a) => Some(a),
- None => Some(&def),
- };
-
- // Building the CStrings from the `str`s within `app_infos`.
- // They need to be created ahead of time, since we pass pointers to them.
- let app_infos_strings = if let Some(app_infos) = app_infos {
- Some((
- app_infos
- .application_name
- .clone()
- .map(|n| CString::new(n.as_bytes().to_owned()).unwrap()),
- app_infos
- .engine_name
- .clone()
- .map(|n| CString::new(n.as_bytes().to_owned()).unwrap()),
- ))
- } else {
- None
- };
-
- // Building the `vk::ApplicationInfo` if required.
- let app_infos = if let Some(app_infos) = app_infos {
- Some(ash::vk::ApplicationInfo {
- p_application_name: app_infos_strings
- .as_ref()
- .unwrap()
- .0
- .as_ref()
- .map(|s| s.as_ptr())
- .unwrap_or(ptr::null()),
- application_version: app_infos
- .application_version
- .map(|v| v.try_into().expect("Version out of range"))
- .unwrap_or(0),
- p_engine_name: app_infos_strings
- .as_ref()
- .unwrap()
- .1
- .as_ref()
- .map(|s| s.as_ptr())
- .unwrap_or(ptr::null()),
- engine_version: app_infos
- .engine_version
- .map(|v| v.try_into().expect("Version out of range"))
- .unwrap_or(0),
- api_version: max_api_version.try_into().expect("Version out of range"),
- ..Default::default()
- })
- } else {
- None
- };
-
- // FIXME: check whether each layer is supported
- let layers_ptrs = layers
- .iter()
- .map(|layer| layer.as_ptr())
- .collect::<SmallVec<[_; 16]>>();
-
- let extensions_list: Vec<CString> = extensions.into();
- let extensions_ptrs = extensions_list
- .iter()
- .map(|extension| extension.as_ptr())
- .collect::<SmallVec<[_; 32]>>();
-
- // Creating the Vulkan instance.
- let instance = unsafe {
- let mut output = MaybeUninit::uninit();
- let infos = ash::vk::InstanceCreateInfo {
- flags: ash::vk::InstanceCreateFlags::empty(),
- p_application_info: if let Some(app) = app_infos.as_ref() {
- app as *const _
- } else {
- ptr::null()
- },
- enabled_layer_count: layers_ptrs.len() as u32,
- pp_enabled_layer_names: layers_ptrs.as_ptr(),
- enabled_extension_count: extensions_ptrs.len() as u32,
- pp_enabled_extension_names: extensions_ptrs.as_ptr(),
- ..Default::default()
- };
-
- let fns = function_pointers.fns();
- check_errors(
- fns.v1_0
- .create_instance(&infos, ptr::null(), output.as_mut_ptr()),
- )?;
- output.assume_init()
- };
-
- // Loading the function pointers of the newly-created instance.
- let fns = {
- InstanceFunctions::load(|name| {
- function_pointers.get_instance_proc_addr(instance, name.as_ptr())
- })
- };
-
- let mut instance = Instance {
- instance,
- api_version,
- max_api_version,
- //alloc: None,
- physical_device_infos: Vec::new(),
- fns,
- extensions: extensions.clone(),
- layers,
- function_pointers,
- };
-
- // Enumerating all physical devices.
- instance.physical_device_infos = init_physical_devices(&instance)?;
-
- Ok(Arc::new(instance))
- }
-
- /*/// Same as `new`, but provides an allocator that will be used by the Vulkan library whenever
- /// it needs to allocate memory on the host.
- ///
- /// Note that this allocator can be overridden when you create a `Device`, a `MemoryPool`, etc.
- pub fn with_alloc(app_infos: Option<&ApplicationInfo>, alloc: Box<Alloc + Send + Sync>) -> Arc<Instance> {
- unimplemented!()
- }*/
-
- /// Returns the Vulkan version supported by the instance.
- ///
- /// This is the lower of the
- /// [driver's supported version](crate::instance::loader::FunctionPointers::api_version) and
- /// [`max_api_version`](Instance::max_api_version).
- #[inline]
- pub fn api_version(&self) -> Version {
- self.api_version
- }
-
- /// Returns the maximum Vulkan version that was specified when creating the instance.
- #[inline]
- pub fn max_api_version(&self) -> Version {
- self.max_api_version
- }
-
- /// Grants access to the Vulkan functions of the instance.
- #[inline]
- pub fn fns(&self) -> &InstanceFunctions {
- &self.fns
- }
-
- /// Returns the extensions that have been enabled on the instance.
- #[inline]
- pub fn enabled_extensions(&self) -> &InstanceExtensions {
- &self.extensions
- }
-
- /// Returns the layers that have been enabled on the instance.
- #[doc(hidden)]
- #[inline]
- pub fn enabled_layers(&self) -> slice::Iter<CString> {
- self.layers.iter()
- }
-}
-
-impl fmt::Debug for Instance {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan instance {:?}>", self.instance)
- }
-}
-
-unsafe impl VulkanObject for Instance {
- type Object = ash::vk::Instance;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Instance {
- self.instance
- }
-}
-
-impl Drop for Instance {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- self.fns.v1_0.destroy_instance(self.instance, ptr::null());
- }
- }
-}
-
-impl PartialEq for Instance {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.instance == other.instance
- }
-}
-
-impl Eq for Instance {}
-
-impl Hash for Instance {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.instance.hash(state);
- }
-}
-
-// Same as Cow but less annoying.
-enum OwnedOrRef<T: 'static> {
- Owned(T),
- Ref(&'static T),
-}
-
-impl<T> Deref for OwnedOrRef<T> {
- type Target = T;
- #[inline]
- fn deref(&self) -> &T {
- match *self {
- OwnedOrRef::Owned(ref v) => v,
- OwnedOrRef::Ref(v) => v,
- }
- }
-}
-
-/// Information that can be given to the Vulkan driver so that it can identify your application.
-// TODO: better documentation for struct and methods
-#[derive(Debug, Clone)]
-pub struct ApplicationInfo<'a> {
- /// Name of the application.
- pub application_name: Option<Cow<'a, str>>,
- /// An opaque number that contains the version number of the application.
- pub application_version: Option<Version>,
- /// Name of the engine used to power the application.
- pub engine_name: Option<Cow<'a, str>>,
- /// An opaque number that contains the version number of the engine.
- pub engine_version: Option<Version>,
-}
-
-impl<'a> ApplicationInfo<'a> {
- /// Builds an `ApplicationInfo` from the information gathered by Cargo.
- ///
- /// # Panic
- ///
- /// - Panics if the required environment variables are missing, which happens if the project
- /// wasn't built by Cargo.
- ///
- #[deprecated(note = "Please use the `app_info_from_cargo_toml!` macro instead")]
- pub fn from_cargo_toml() -> ApplicationInfo<'a> {
- let version = Version {
- major: 0,
- minor: 0,
- patch: 0,
- };
-
- let name = "";
-
- ApplicationInfo {
- application_name: Some(name.into()),
- application_version: Some(version),
- engine_name: None,
- engine_version: None,
- }
- }
-}
-
-/// Builds an `ApplicationInfo` from the information gathered by Cargo.
-///
-/// # Panic
-///
-/// - Panics if the required environment variables are missing, which happens if the project
-/// wasn't built by Cargo.
-///
-#[macro_export]
-macro_rules! app_info_from_cargo_toml {
- () => {{
- let version = $crate::instance::Version {
- major: 0,
- minor: 0,
- patch: 0,
- };
-
- let name = "";
-
- $crate::instance::ApplicationInfo {
- application_name: Some(name.into()),
- application_version: Some(version),
- engine_name: None,
- engine_version: None,
- }
- }};
-}
-
-impl<'a> Default for ApplicationInfo<'a> {
- fn default() -> ApplicationInfo<'a> {
- ApplicationInfo {
- application_name: None,
- application_version: None,
- engine_name: None,
- engine_version: None,
- }
- }
-}
-
-/// Error that can happen when creating an instance.
-#[derive(Clone, Debug)]
-pub enum InstanceCreationError {
- /// Failed to load the Vulkan shared library.
- LoadingError(LoadingError),
- /// Not enough memory.
- OomError(OomError),
- /// Failed to initialize for an implementation-specific reason.
- InitializationFailed,
- /// One of the requested layers is missing.
- LayerNotPresent,
- /// One of the requested extensions is not supported by the implementation.
- ExtensionNotPresent,
- /// The version requested is not supported by the implementation.
- IncompatibleDriver,
- /// A restriction for an extension was not met.
- ExtensionRestrictionNotMet(ExtensionRestrictionError),
-}
-
-impl error::Error for InstanceCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- InstanceCreationError::LoadingError(ref err) => Some(err),
- InstanceCreationError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for InstanceCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- match *self {
- InstanceCreationError::LoadingError(_) => {
- write!(fmt, "failed to load the Vulkan shared library")
- }
- InstanceCreationError::OomError(_) => write!(fmt, "not enough memory available"),
- InstanceCreationError::InitializationFailed => write!(fmt, "initialization failed"),
- InstanceCreationError::LayerNotPresent => write!(fmt, "layer not present"),
- InstanceCreationError::ExtensionNotPresent => write!(fmt, "extension not present"),
- InstanceCreationError::IncompatibleDriver => write!(fmt, "incompatible driver"),
- InstanceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
- }
- }
-}
-
-impl From<OomError> for InstanceCreationError {
- #[inline]
- fn from(err: OomError) -> InstanceCreationError {
- InstanceCreationError::OomError(err)
- }
-}
-
-impl From<LoadingError> for InstanceCreationError {
- #[inline]
- fn from(err: LoadingError) -> InstanceCreationError {
- InstanceCreationError::LoadingError(err)
- }
-}
-
-impl From<ExtensionRestrictionError> for InstanceCreationError {
- #[inline]
- fn from(err: ExtensionRestrictionError) -> Self {
- Self::ExtensionRestrictionNotMet(err)
- }
-}
-
-impl From<Error> for InstanceCreationError {
- #[inline]
- fn from(err: Error) -> InstanceCreationError {
- match err {
- err @ Error::OutOfHostMemory => InstanceCreationError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => InstanceCreationError::OomError(OomError::from(err)),
- Error::InitializationFailed => InstanceCreationError::InitializationFailed,
- Error::LayerNotPresent => InstanceCreationError::LayerNotPresent,
- Error::ExtensionNotPresent => InstanceCreationError::ExtensionNotPresent,
- Error::IncompatibleDriver => InstanceCreationError::IncompatibleDriver,
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::device::physical::PhysicalDevice;
-
- #[test]
- fn create_instance() {
- let _ = instance!();
- }
-
- #[test]
- fn queue_family_by_id() {
- let instance = instance!();
-
- let phys = match PhysicalDevice::enumerate(&instance).next() {
- Some(p) => p,
- None => return,
- };
-
- let queue_family = match phys.queue_families().next() {
- Some(q) => q,
- None => return,
- };
-
- let by_id = phys.queue_family_by_id(queue_family.id()).unwrap();
- assert_eq!(by_id.id(), queue_family.id());
- }
-}
diff --git a/src/instance/layers.rs b/src/instance/layers.rs
index 6c56090..3ea264b 100644
--- a/src/instance/layers.rs
+++ b/src/instance/layers.rs
@@ -7,79 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::ptr;
-use std::vec::IntoIter;
-
-use crate::check_errors;
-use crate::instance::loader;
-use crate::instance::loader::LoadingError;
-use crate::Error;
-use crate::OomError;
use crate::Version;
-
-/// Queries the list of layers that are available when creating an instance.
-///
-/// On success, this function returns an iterator that produces
-/// [`LayerProperties`](struct.LayerProperties.html) objects. In order to enable a layer, you need
-/// to pass its name (returned by `LayerProperties::name()`) when creating the
-/// [`Instance`](struct.Instance.html).
-///
-/// This function returns an error if it failed to load the Vulkan library.
-///
-/// > **Note**: It is possible that one of the layers enumerated here is no longer available when
-/// > you create the `Instance`. This will lead to an error when calling `Instance::new`. The
-/// > author isn't aware of any situation where this would happen, but it is theoretically possible
-/// > according to the specifications.
-///
-/// # Example
-///
-/// ```no_run
-/// use vulkano::instance;
-///
-/// for layer in instance::layers_list().unwrap() {
-/// println!("Available layer: {}", layer.name());
-/// }
-/// ```
-pub fn layers_list() -> Result<LayersIterator, LayersListError> {
- layers_list_from_loader(loader::auto_loader()?)
-}
-
-/// Same as `layers_list()`, but allows specifying a loader.
-pub fn layers_list_from_loader<L>(
- ptrs: &loader::FunctionPointers<L>,
-) -> Result<LayersIterator, LayersListError>
-where
- L: loader::Loader,
-{
- unsafe {
- let fns = ptrs.fns();
-
- let mut num = 0;
- check_errors(
- fns.v1_0
- .enumerate_instance_layer_properties(&mut num, ptr::null_mut()),
- )?;
-
- let mut layers: Vec<ash::vk::LayerProperties> = Vec::with_capacity(num as usize);
- check_errors({
- fns.v1_0
- .enumerate_instance_layer_properties(&mut num, layers.as_mut_ptr())
- })?;
- layers.set_len(num as usize);
-
- Ok(LayersIterator {
- iter: layers.into_iter(),
- })
- }
-}
+use std::ffi::CStr;
/// Properties of a layer.
#[derive(Clone)]
pub struct LayerProperties {
- props: ash::vk::LayerProperties,
+ pub(crate) props: ash::vk::LayerProperties,
}
impl LayerProperties {
@@ -88,12 +22,14 @@ impl LayerProperties {
/// If you want to enable this layer on an instance, you need to pass this value to
/// `Instance::new`.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
+ /// use vulkano::VulkanLibrary;
///
- /// for layer in instance::layers_list().unwrap() {
+ /// let library = VulkanLibrary::new().unwrap();
+ ///
+ /// for layer in library.layer_properties().unwrap() {
/// println!("Layer name: {}", layer.name());
/// }
/// ```
@@ -110,12 +46,14 @@ impl LayerProperties {
///
/// This description is chosen by the layer itself.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
+ /// use vulkano::VulkanLibrary;
+ ///
+ /// let library = VulkanLibrary::new().unwrap();
///
- /// for layer in instance::layers_list().unwrap() {
+ /// for layer in library.layer_properties().unwrap() {
/// println!("Layer description: {}", layer.description());
/// }
/// ```
@@ -130,13 +68,14 @@ impl LayerProperties {
/// Returns the version of Vulkan supported by this layer.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
- /// use vulkano::instance::Version;
+ /// use vulkano::{Version, VulkanLibrary};
+ ///
+ /// let library = VulkanLibrary::new().unwrap();
///
- /// for layer in instance::layers_list().unwrap() {
+ /// for layer in library.layer_properties().unwrap() {
/// if layer.vulkan_version() >= Version::major_minor(2, 0) {
/// println!("Layer {} requires Vulkan 2.0", layer.name());
/// }
@@ -151,12 +90,14 @@ impl LayerProperties {
///
/// The number is chosen by the layer itself. It can be used for bug reports for example.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
+ /// use vulkano::VulkanLibrary;
///
- /// for layer in instance::layers_list().unwrap() {
+ /// let library = VulkanLibrary::new().unwrap();
+ ///
+ /// for layer in library.layer_properties().unwrap() {
/// println!("Layer {} - Version: {}", layer.name(), layer.implementation_version());
/// }
/// ```
@@ -166,97 +107,22 @@ impl LayerProperties {
}
}
-/// Error that can happen when loading the list of layers.
-#[derive(Clone, Debug)]
-pub enum LayersListError {
- /// Failed to load the Vulkan shared library.
- LoadingError(LoadingError),
- /// Not enough memory.
- OomError(OomError),
-}
-
-impl error::Error for LayersListError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- LayersListError::LoadingError(ref err) => Some(err),
- LayersListError::OomError(ref err) => Some(err),
- }
- }
-}
-
-impl fmt::Display for LayersListError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- LayersListError::LoadingError(_) => "failed to load the Vulkan shared library",
- LayersListError::OomError(_) => "not enough memory available",
- }
- )
- }
-}
-
-impl From<OomError> for LayersListError {
- #[inline]
- fn from(err: OomError) -> LayersListError {
- LayersListError::OomError(err)
- }
-}
-
-impl From<LoadingError> for LayersListError {
- #[inline]
- fn from(err: LoadingError) -> LayersListError {
- LayersListError::LoadingError(err)
- }
-}
-
-impl From<Error> for LayersListError {
- #[inline]
- fn from(err: Error) -> LayersListError {
- match err {
- err @ Error::OutOfHostMemory => LayersListError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => LayersListError::OomError(OomError::from(err)),
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-/// Iterator that produces the list of layers that are available.
-// TODO: #[derive(Debug, Clone)]
-pub struct LayersIterator {
- iter: IntoIter<ash::vk::LayerProperties>,
-}
-
-impl Iterator for LayersIterator {
- type Item = LayerProperties;
-
- #[inline]
- fn next(&mut self) -> Option<LayerProperties> {
- self.iter.next().map(|p| LayerProperties { props: p })
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-impl ExactSizeIterator for LayersIterator {}
-
#[cfg(test)]
mod tests {
- use crate::instance;
+ use crate::VulkanLibrary;
#[test]
fn layers_list() {
- let mut list = match instance::layers_list() {
+ let library = match VulkanLibrary::new() {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ let list = match library.layer_properties() {
Ok(l) => l,
Err(_) => return,
};
- while let Some(_) = list.next() {}
+ for _ in list {}
}
}
diff --git a/src/instance/loader.rs b/src/instance/loader.rs
deleted file mode 100644
index 7714fd2..0000000
--- a/src/instance/loader.rs
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Vulkan implementation loading system.
-//!
-//! Before vulkano can do anything, it first needs to find an implementation of Vulkan. A Vulkan
-//! implementation is defined as a single `vkGetInstanceProcAddr` function, which can be accessed
-//! through the `Loader` trait.
-//!
-//! This module provides various implementations of the `Loader` trait.
-//!
-//! Once you have a struct that implements `Loader`, you can create a `FunctionPointers` struct
-//! from it and use this `FunctionPointers` struct to build an `Instance`.
-//!
-//! By default vulkano will use the `auto_loader()` function, which tries to automatically load
-//! a Vulkan implementation from the system.
-
-use crate::check_errors;
-use crate::fns::EntryFunctions;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::Version;
-use lazy_static::lazy_static;
-use shared_library;
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::mem;
-use std::ops::Deref;
-use std::os::raw::c_char;
-use std::os::raw::c_void;
-use std::path::Path;
-
-/// Implemented on objects that grant access to a Vulkan implementation.
-pub unsafe trait Loader {
- /// Calls the `vkGetInstanceProcAddr` function. The parameters are the same.
- ///
- /// The returned function must stay valid for as long as `self` is alive.
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void;
-}
-
-unsafe impl<T> Loader for T
-where
- T: SafeDeref,
- T::Target: Loader,
-{
- #[inline]
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void {
- (**self).get_instance_proc_addr(instance, name)
- }
-}
-
-/// Implementation of `Loader` that loads Vulkan from a dynamic library.
-pub struct DynamicLibraryLoader {
- vk_lib: shared_library::dynamic_library::DynamicLibrary,
- get_proc_addr:
- extern "system" fn(instance: ash::vk::Instance, pName: *const c_char) -> *const c_void,
-}
-
-impl DynamicLibraryLoader {
- /// Tries to load the dynamic library at the given path, and tries to
- /// load `vkGetInstanceProcAddr` in it.
- ///
- /// # Safety
- ///
- /// - The dynamic library must be a valid Vulkan implementation.
- ///
- pub unsafe fn new<P>(path: P) -> Result<DynamicLibraryLoader, LoadingError>
- where
- P: AsRef<Path>,
- {
- let vk_lib = shared_library::dynamic_library::DynamicLibrary::open(Some(path.as_ref()))
- .map_err(LoadingError::LibraryLoadFailure)?;
-
- let get_proc_addr = {
- let ptr: *mut c_void = vk_lib
- .symbol("vkGetInstanceProcAddr")
- .map_err(|_| LoadingError::MissingEntryPoint("vkGetInstanceProcAddr".to_owned()))?;
- mem::transmute(ptr)
- };
-
- Ok(DynamicLibraryLoader {
- vk_lib,
- get_proc_addr,
- })
- }
-}
-
-unsafe impl Loader for DynamicLibraryLoader {
- #[inline]
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void {
- (self.get_proc_addr)(instance, name)
- }
-}
-
-/// Wraps around a loader and contains function pointers.
-pub struct FunctionPointers<L> {
- loader: L,
- fns: EntryFunctions,
-}
-
-impl<L> FunctionPointers<L> {
- /// Loads some global function pointer from the loader.
- pub fn new(loader: L) -> FunctionPointers<L>
- where
- L: Loader,
- {
- let fns = EntryFunctions::load(|name| unsafe {
- mem::transmute(loader.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr()))
- });
-
- FunctionPointers { loader, fns }
- }
-
- /// Returns the collection of Vulkan entry points from the Vulkan loader.
- #[inline]
- pub fn fns(&self) -> &EntryFunctions {
- &self.fns
- }
-
- /// Returns the highest Vulkan version that is supported for instances.
- pub fn api_version(&self) -> Result<Version, OomError>
- where
- L: Loader,
- {
- // Per the Vulkan spec:
- // If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a
- // Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion
- // to determine the version of Vulkan.
- unsafe {
- let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0");
- let func = self.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr());
-
- if func.is_null() {
- Ok(Version {
- major: 1,
- minor: 0,
- patch: 0,
- })
- } else {
- type Pfn = extern "system" fn(pApiVersion: *mut u32) -> ash::vk::Result;
- let func: Pfn = mem::transmute(func);
- let mut api_version = 0;
- check_errors(func(&mut api_version))?;
- Ok(Version::from(api_version))
- }
- }
- }
-
- /// Calls `get_instance_proc_addr` on the underlying loader.
- #[inline]
- pub fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void
- where
- L: Loader,
- {
- self.loader.get_instance_proc_addr(instance, name)
- }
-}
-
-/// Expression that returns a loader that assumes that Vulkan is linked to the executable you're
-/// compiling.
-///
-/// If you use this macro, you must linked to a library that provides the `vkGetInstanceProcAddr`
-/// symbol.
-///
-/// This is provided as a macro and not as a regular function, because the macro contains an
-/// `extern {}` block.
-// TODO: should this be unsafe?
-#[macro_export]
-macro_rules! statically_linked_vulkan_loader {
- () => {{
- extern "C" {
- fn vkGetInstanceProcAddr(
- instance: ash::vk::Instance,
- pName: *const c_char,
- ) -> ash::vk::PFN_vkVoidFunction;
- }
-
- struct StaticallyLinkedVulkanLoader;
- unsafe impl Loader for StaticallyLinkedVulkanLoader {
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> extern "system" fn() -> () {
- unsafe { vkGetInstanceProcAddr(instance, name) }
- }
- }
-
- StaticallyLinkedVulkanLoader
- }};
-}
-
-/// Returns the default `FunctionPointers` for this system.
-///
-/// This function tries to auto-guess where to find the Vulkan implementation, and loads it in a
-/// `lazy_static!`. The content of the lazy_static is then returned, or an error if we failed to
-/// load Vulkan.
-pub fn auto_loader(
-) -> Result<&'static FunctionPointers<Box<dyn Loader + Send + Sync>>, LoadingError> {
- #[cfg(target_os = "ios")]
- #[allow(non_snake_case)]
- fn def_loader_impl() -> Result<Box<Loader + Send + Sync>, LoadingError> {
- let loader = statically_linked_vulkan_loader!();
- Ok(Box::new(loader))
- }
-
- #[cfg(not(target_os = "ios"))]
- fn def_loader_impl() -> Result<Box<dyn Loader + Send + Sync>, LoadingError> {
- #[cfg(windows)]
- fn get_path() -> &'static Path {
- Path::new("vulkan-1.dll")
- }
- #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
- fn get_path() -> &'static Path {
- Path::new("libvulkan.so.1")
- }
- #[cfg(target_os = "macos")]
- fn get_path() -> &'static Path {
- Path::new("libvulkan.1.dylib")
- }
- #[cfg(target_os = "android")]
- fn get_path() -> &'static Path {
- Path::new("libvulkan.so")
- }
-
- let loader = unsafe { DynamicLibraryLoader::new(get_path())? };
-
- Ok(Box::new(loader))
- }
-
- lazy_static! {
- static ref DEFAULT_LOADER: Result<FunctionPointers<Box<dyn Loader + Send + Sync>>, LoadingError> =
- def_loader_impl().map(FunctionPointers::new);
- }
-
- match DEFAULT_LOADER.deref() {
- &Ok(ref ptr) => Ok(ptr),
- &Err(ref err) => Err(err.clone()),
- }
-}
-
-/// Error that can happen when loading the Vulkan loader.
-#[derive(Debug, Clone)]
-pub enum LoadingError {
- /// Failed to load the Vulkan shared library.
- LibraryLoadFailure(String), // TODO: meh for error type, but this needs changes in shared_library
-
- /// One of the entry points required to be supported by the Vulkan implementation is missing.
- MissingEntryPoint(String),
-}
-
-impl error::Error for LoadingError {
- /*#[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- LoadingError::LibraryLoadFailure(ref err) => Some(err),
- _ => None
- }
- }*/
-}
-
-impl fmt::Display for LoadingError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- LoadingError::LibraryLoadFailure(_) => "failed to load the Vulkan shared library",
- LoadingError::MissingEntryPoint(_) => {
- "one of the entry points required to be supported by the Vulkan implementation \
- is missing"
- }
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::instance::loader::DynamicLibraryLoader;
- use crate::instance::loader::LoadingError;
-
- #[test]
- fn dl_open_error() {
- unsafe {
- match DynamicLibraryLoader::new("_non_existing_library.void") {
- Err(LoadingError::LibraryLoadFailure(_)) => (),
- _ => panic!(),
- }
- }
- }
-}
diff --git a/src/instance/mod.rs b/src/instance/mod.rs
index 5e85e7f..55e0626 100644
--- a/src/instance/mod.rs
+++ b/src/instance/mod.rs
@@ -9,32 +9,35 @@
//! API entry point.
//!
-//! The first thing to do before you start using Vulkan is to create an `Instance` object.
+//! The first thing to do after loading the Vulkan library is to create an `Instance` object.
//!
//! For example:
//!
//! ```no_run
-//! use vulkano::instance::Instance;
-//! use vulkano::instance::InstanceExtensions;
-//! use vulkano::Version;
-//!
-//! let instance = match Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None) {
-//! Ok(i) => i,
-//! Err(err) => panic!("Couldn't build instance: {:?}", err)
+//! use vulkano::{
+//! instance::{Instance, InstanceExtensions},
+//! Version, VulkanLibrary,
//! };
+//!
+//! let library = VulkanLibrary::new()
+//! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err));
+//! let instance = Instance::new(library, Default::default())
+//! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err));
//! ```
//!
//! Creating an instance initializes everything and allows you to enumerate physical devices,
//! ie. all the Vulkan implementations that are available on the system.
//!
//! ```no_run
-//! # use vulkano::instance::Instance;
-//! # use vulkano::instance::InstanceExtensions;
-//! # use vulkano::Version;
+//! # use vulkano::{
+//! # instance::{Instance, InstanceExtensions},
+//! # Version, VulkanLibrary,
+//! # };
//! use vulkano::device::physical::PhysicalDevice;
//!
-//! # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
-//! for physical_device in PhysicalDevice::enumerate(&instance) {
+//! # let library = VulkanLibrary::new().unwrap();
+//! # let instance = Instance::new(library, Default::default()).unwrap();
+//! for physical_device in instance.enumerate_physical_devices().unwrap() {
//! println!("Available device: {}", physical_device.properties().device_name);
//! }
//! ```
@@ -42,7 +45,7 @@
//! # Enumerating physical devices and creating a device
//!
//! After you have created an instance, the next step is usually to enumerate the physical devices
-//! that are available on the system with `PhysicalDevice::enumerate()` (see above).
+//! that are available on the system with `Instance::enumerate_physical_devices()` (see above).
//!
//! When choosing which physical device to use, keep in mind that physical devices may or may not
//! be able to draw to a certain surface (ie. to a window or a monitor), or may even not be able
@@ -50,23 +53,844 @@
//!
//! Once you have chosen a physical device, you can create a `Device` object from it. See the
//! `device` module for more info.
+//!
+//! # Portability subset devices and the `enumerate_portability` flag
+//!
+//! Certain devices, currently those on MacOS and iOS systems, do not fully conform to the Vulkan
+//! specification. They are usable as normal devices, but they do not implement everything that
+//! is required; some mandatory parts of Vulkan are missing. These are known as
+//! "portability subset" devices.
+//!
+//! A portability subset device will advertise support for the
+//! [`khr_portability_subset`](crate::device::DeviceExtensions::khr_portability_subset) device
+//! extension. This extension must always be enabled when it is supported, and Vulkano will
+//! automatically enable it when creating the device. When it is enabled, some parts of Vulkan that
+//! are available in standard Vulkan will not be available by default, but they can be used by
+//! enabling corresponding features when creating the device, if the device supports them.
+//!
+//! Because these devices are non-conformant, Vulkan programs that rely on full compliance may
+//! not work (crash or have validation errors) when run on them, if they happen to use a part of
+//! Vulkan that is missing from the non-conformant device. Therefore, Vulkan hides them from
+//! the user by default when calling `enumerate_physical_devices` on the instance. If there are no
+//! conformant devices on the system, `Instance::new` will return an `IncompatibleDriver` error.
+//!
+//! In order to enumerate portability subset devices, you must set the
+//! [`InstanceCreateInfo::enumerate_portability`] flag when creating the instance. However, if you
+//! do this, your program must be prepared to handle the non-conformant aspects of these devices,
+//! and must enable the appropriate features when creating the `Device` if you intend to use them.
-pub use self::extensions::InstanceExtensions;
-pub use self::instance::ApplicationInfo;
-pub use self::instance::Instance;
-pub use self::instance::InstanceCreationError;
-pub use self::layers::layers_list;
-pub use self::layers::LayerProperties;
-pub use self::layers::LayersIterator;
-pub use self::layers::LayersListError;
-pub use self::loader::LoadingError;
-pub use crate::extensions::{
- ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
+use self::debug::{
+ DebugUtilsMessengerCreateInfo, UserCallback, ValidationFeatureDisable, ValidationFeatureEnable,
+};
+pub use self::{extensions::InstanceExtensions, layers::LayerProperties};
+use crate::{
+ device::physical::PhysicalDevice, instance::debug::trampoline, macros::impl_id_counter,
+ OomError, RequiresOneOf, VulkanError, VulkanLibrary, VulkanObject,
+};
+pub use crate::{
+ extensions::{ExtensionRestriction, ExtensionRestrictionError},
+ fns::InstanceFunctions,
+ version::Version,
+};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ ffi::{c_void, CString},
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ panic::{RefUnwindSafe, UnwindSafe},
+ ptr,
+ sync::Arc,
};
-pub use crate::version::Version;
pub mod debug;
pub(crate) mod extensions;
-mod instance;
mod layers;
-pub mod loader;
+
+/// An instance of a Vulkan context. This is the main object that should be created by an
+/// application before everything else.
+///
+/// # Application and engine info
+///
+/// When you create an instance, you have the possibility to set information about your application
+/// and its engine.
+///
+/// Providing this information allows for example the driver to let the user configure the driver's
+/// behavior for your application alone through a control panel.
+///
+/// ```no_run
+/// # #[macro_use] extern crate vulkano;
+/// # fn main() {
+/// use vulkano::{
+/// instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+/// Version, VulkanLibrary,
+/// };
+///
+/// let library = VulkanLibrary::new().unwrap();
+/// let _instance = Instance::new(
+/// library,
+/// InstanceCreateInfo::application_from_cargo_toml(),
+/// ).unwrap();
+/// # }
+/// ```
+///
+/// # API versions
+///
+/// Both an `Instance` and a [`Device`](crate::device::Device) have a highest version of the Vulkan
+/// API that they support. This places a limit on what Vulkan functions and features are available
+/// to use when used on a particular instance or device. It is possible for the instance and the
+/// device to support different versions. The supported version for an instance can be queried
+/// before creation with
+/// [`VulkanLibrary::api_version`](crate::VulkanLibrary::api_version),
+/// while for a device it can be retrieved with
+/// [`PhysicalDevice::api_version`](crate::device::physical::PhysicalDevice::api_version).
+///
+/// When creating an `Instance`, you have to specify a maximum API version that you will use.
+/// This restricts the API version that is available for the instance and any devices created from
+/// it. For example, if both instance and device potentially support Vulkan 1.2, but you specify
+/// 1.1 as the maximum API version when creating the `Instance`, then you can only use Vulkan 1.1
+/// functions, even though they could theoretically support a higher version. You can think of it
+/// as a promise never to use any functionality from a higher version.
+///
+/// The maximum API version is not a _minimum_, so it is possible to set it to a higher version than
+/// what the instance or device inherently support. The final API version that you are able to use
+/// on an instance or device is the lower of the supported API version and the chosen maximum API
+/// version of the `Instance`.
+///
+/// Due to a quirk in how the Vulkan 1.0 specification was written, if the instance only
+/// supports Vulkan 1.0, then it is not possible to specify a maximum API version higher than 1.0.
+/// Trying to create an `Instance` will return an `IncompatibleDriver` error. Consequently, it is
+/// not possible to use a higher device API version with an instance that only supports 1.0.
+///
+/// # Extensions
+///
+/// When creating an `Instance`, you must provide a list of extensions that must be enabled on the
+/// newly-created instance. Trying to enable an extension that is not supported by the system will
+/// result in an error.
+///
+/// Contrary to OpenGL, it is not possible to use the features of an extension if it was not
+/// explicitly enabled.
+///
+/// Extensions are especially important to take into account if you want to render images on the
+/// screen, as the only way to do so is to use the `VK_KHR_surface` extension. More information
+/// about this in the `swapchain` module.
+///
+/// For example, here is how we create an instance with the `VK_KHR_surface` and
+/// `VK_KHR_android_surface` extensions enabled, which will allow us to render images to an
+/// Android screen. You can compile and run this code on any system, but it is highly unlikely to
+/// succeed on anything else than an Android-running device.
+///
+/// ```no_run
+/// use vulkano::{
+/// instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+/// Version, VulkanLibrary,
+/// };
+///
+/// let library = VulkanLibrary::new()
+/// .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err));
+///
+/// let extensions = InstanceExtensions {
+/// khr_surface: true,
+/// khr_android_surface: true,
+/// .. InstanceExtensions::empty()
+/// };
+///
+/// let instance = Instance::new(
+/// library,
+/// InstanceCreateInfo {
+/// enabled_extensions: extensions,
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err));
+/// ```
+///
+/// # Layers
+///
+/// When creating an `Instance`, you have the possibility to pass a list of **layers** that will
+/// be activated on the newly-created instance. The list of available layers can be retrieved by
+/// calling the [`layer_properties`](crate::VulkanLibrary::layer_properties) method of
+/// `VulkanLibrary`.
+///
+/// A layer is a component that will hook and potentially modify the Vulkan function calls.
+/// For example, activating a layer could add a frames-per-second counter on the screen, or it
+/// could send information to a debugger that will debug your application.
+///
+/// > **Note**: From an application's point of view, layers "just exist". In practice, on Windows
+/// > and Linux, layers can be installed by third party installers or by package managers and can
+/// > also be activated by setting the value of the `VK_INSTANCE_LAYERS` environment variable
+/// > before starting the program. See the documentation of the official Vulkan loader for these
+/// > platforms.
+///
+/// > **Note**: In practice, the most common use of layers right now is for debugging purposes.
+/// > To do so, you are encouraged to set the `VK_INSTANCE_LAYERS` environment variable on Windows
+/// > or Linux instead of modifying the source code of your program. For example:
+/// > `export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump` on Linux if you installed the Vulkan SDK
+/// > will print the list of raw Vulkan function calls.
+///
+/// ## Examples
+///
+/// ```
+/// # use std::{sync::Arc, error::Error};
+/// # use vulkano::{
+/// # instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+/// # Version, VulkanLibrary,
+/// # };
+/// # fn test() -> Result<Arc<Instance>, Box<dyn Error>> {
+/// let library = VulkanLibrary::new()?;
+///
+/// // For the sake of the example, we activate all the layers that
+/// // contain the word "foo" in their description.
+/// let layers: Vec<_> = library.layer_properties()?
+/// .filter(|l| l.description().contains("foo"))
+/// .collect();
+///
+/// let instance = Instance::new(
+/// library,
+/// InstanceCreateInfo {
+/// enabled_layers: layers.iter().map(|l| l.name().to_owned()).collect(),
+/// ..Default::default()
+/// },
+/// )?;
+/// # Ok(instance)
+/// # }
+/// ```
+// TODO: mention that extensions must be supported by layers as well
+pub struct Instance {
+ handle: ash::vk::Instance,
+ fns: InstanceFunctions,
+ id: NonZeroU64,
+
+ api_version: Version,
+ enabled_extensions: InstanceExtensions,
+ enabled_layers: Vec<String>,
+ library: Arc<VulkanLibrary>,
+ max_api_version: Version,
+ _user_callbacks: Vec<Box<UserCallback>>,
+}
+
+// TODO: fix the underlying cause instead
+impl UnwindSafe for Instance {}
+impl RefUnwindSafe for Instance {}
+
+impl Instance {
+ /// Creates a new `Instance`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if any version numbers in `create_info` contain a field too large to be converted
+ /// into a Vulkan version number.
+ /// - Panics if `create_info.max_api_version` is not at least `V1_0`.
+ pub fn new(
+ library: Arc<VulkanLibrary>,
+ create_info: InstanceCreateInfo,
+ ) -> Result<Arc<Instance>, InstanceCreationError> {
+ unsafe { Self::with_debug_utils_messengers(library, create_info, []) }
+ }
+
+ /// Creates a new `Instance` with debug messengers to use during the creation and destruction
+ /// of the instance.
+ ///
+ /// The debug messengers are not used at any other time,
+ /// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger) should be used for
+ /// that.
+ ///
+ /// If `debug_utils_messengers` is not empty, the `ext_debug_utils` extension must be set in
+ /// `enabled_extensions`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the `message_severity` or `message_type` members of any element of
+ /// `debug_utils_messengers` are empty.
+ ///
+ /// # Safety
+ ///
+ /// - The `user_callback` of each element of `debug_utils_messengers` must not make any calls
+ /// to the Vulkan API.
+ pub unsafe fn with_debug_utils_messengers(
+ library: Arc<VulkanLibrary>,
+ create_info: InstanceCreateInfo,
+ debug_utils_messengers: impl IntoIterator<Item = DebugUtilsMessengerCreateInfo>,
+ ) -> Result<Arc<Instance>, InstanceCreationError> {
+ let InstanceCreateInfo {
+ application_name,
+ application_version,
+ mut enabled_extensions,
+ enabled_layers,
+ engine_name,
+ engine_version,
+ max_api_version,
+ enumerate_portability,
+ enabled_validation_features,
+ disabled_validation_features,
+ _ne: _,
+ } = create_info;
+
+ let (api_version, max_api_version) = {
+ let api_version = library.api_version();
+ let max_api_version = if let Some(max_api_version) = max_api_version {
+ max_api_version
+ } else if api_version < Version::V1_1 {
+ api_version
+ } else {
+ Version::HEADER_VERSION
+ };
+
+ (std::cmp::min(max_api_version, api_version), max_api_version)
+ };
+
+ // VUID-VkApplicationInfo-apiVersion-04010
+ assert!(max_api_version >= Version::V1_0);
+ let supported_extensions =
+ library.supported_extensions_with_layers(enabled_layers.iter().map(String::as_str))?;
+ let mut flags = ash::vk::InstanceCreateFlags::empty();
+
+ if enumerate_portability && supported_extensions.khr_portability_enumeration {
+ enabled_extensions.khr_portability_enumeration = true;
+ flags |= ash::vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
+ }
+
+ // Check if the extensions are correct
+ enabled_extensions.check_requirements(&supported_extensions, api_version)?;
+
+ // FIXME: check whether each layer is supported
+ let enabled_layers_cstr: Vec<CString> = enabled_layers
+ .iter()
+ .map(|name| CString::new(name.clone()).unwrap())
+ .collect();
+ let enabled_layers_ptrs = enabled_layers_cstr
+ .iter()
+ .map(|layer| layer.as_ptr())
+ .collect::<SmallVec<[_; 2]>>();
+
+ let enabled_extensions_cstr: Vec<CString> = (&enabled_extensions).into();
+ let enabled_extensions_ptrs = enabled_extensions_cstr
+ .iter()
+ .map(|extension| extension.as_ptr())
+ .collect::<SmallVec<[_; 2]>>();
+
+ let application_name_cstr = application_name.map(|name| CString::new(name).unwrap());
+ let engine_name_cstr = engine_name.map(|name| CString::new(name).unwrap());
+ let application_info = ash::vk::ApplicationInfo {
+ p_application_name: application_name_cstr
+ .as_ref()
+ .map(|s| s.as_ptr())
+ .unwrap_or(ptr::null()),
+ application_version: application_version
+ .try_into()
+ .expect("Version out of range"),
+ p_engine_name: engine_name_cstr
+ .as_ref()
+ .map(|s| s.as_ptr())
+ .unwrap_or(ptr::null()),
+ engine_version: engine_version.try_into().expect("Version out of range"),
+ api_version: max_api_version.try_into().expect("Version out of range"),
+ ..Default::default()
+ };
+
+ let enable_validation_features_vk: SmallVec<[_; 5]> = enabled_validation_features
+ .iter()
+ .copied()
+ .map(Into::into)
+ .collect();
+ let disable_validation_features_vk: SmallVec<[_; 8]> = disabled_validation_features
+ .iter()
+ .copied()
+ .map(Into::into)
+ .collect();
+
+ let mut create_info_vk = ash::vk::InstanceCreateInfo {
+ flags,
+ p_application_info: &application_info,
+ enabled_layer_count: enabled_layers_ptrs.len() as u32,
+ pp_enabled_layer_names: enabled_layers_ptrs.as_ptr(),
+ enabled_extension_count: enabled_extensions_ptrs.len() as u32,
+ pp_enabled_extension_names: enabled_extensions_ptrs.as_ptr(),
+ ..Default::default()
+ };
+ let mut validation_features_vk = None;
+
+ if !enabled_validation_features.is_empty() || !disabled_validation_features.is_empty() {
+ if !enabled_extensions.ext_validation_features {
+ return Err(InstanceCreationError::RequirementNotMet {
+ required_for: "`create_info.enabled_validation_features` or \
+ `create_info.disabled_validation_features` are not empty",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_validation_features"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02967
+ assert!(
+ !enabled_validation_features
+ .contains(&ValidationFeatureEnable::GpuAssistedReserveBindingSlot)
+ || enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted)
+ );
+
+ // VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02968
+ assert!(
+ !(enabled_validation_features.contains(&ValidationFeatureEnable::DebugPrintf)
+ && enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted))
+ );
+
+ let next = validation_features_vk.insert(ash::vk::ValidationFeaturesEXT {
+ enabled_validation_feature_count: enable_validation_features_vk.len() as u32,
+ p_enabled_validation_features: enable_validation_features_vk.as_ptr(),
+ disabled_validation_feature_count: disable_validation_features_vk.len() as u32,
+ p_disabled_validation_features: disable_validation_features_vk.as_ptr(),
+ ..Default::default()
+ });
+
+ next.p_next = create_info_vk.p_next;
+ create_info_vk.p_next = next as *const _ as *const _;
+ }
+
+ // Handle debug messengers
+ let debug_utils_messengers = debug_utils_messengers.into_iter();
+ let mut debug_utils_messenger_create_infos =
+ Vec::with_capacity(debug_utils_messengers.size_hint().0);
+ let mut user_callbacks = Vec::with_capacity(debug_utils_messengers.size_hint().0);
+
+ for create_info in debug_utils_messengers {
+ let DebugUtilsMessengerCreateInfo {
+ message_type,
+ message_severity,
+ user_callback,
+ _ne: _,
+ } = create_info;
+
+ // VUID-VkInstanceCreateInfo-pNext-04926
+ if !enabled_extensions.ext_debug_utils {
+ return Err(InstanceCreationError::RequirementNotMet {
+ required_for: "`create_info.debug_utils_messengers` is not empty",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
+ // TODO: message_severity.validate_instance()?;
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
+ assert!(!message_severity.is_empty());
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
+ // TODO: message_type.validate_instance()?;
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
+ assert!(!message_type.is_empty());
+
+ // VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
+ // Can't be checked, creation is unsafe.
+
+ let user_callback = Box::new(user_callback);
+ let create_info = ash::vk::DebugUtilsMessengerCreateInfoEXT {
+ flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
+ message_severity: message_severity.into(),
+ message_type: message_type.into(),
+ pfn_user_callback: Some(trampoline),
+ p_user_data: &*user_callback as &Arc<_> as *const Arc<_> as *const c_void as *mut _,
+ ..Default::default()
+ };
+
+ debug_utils_messenger_create_infos.push(create_info);
+ user_callbacks.push(user_callback);
+ }
+
+ for i in 1..debug_utils_messenger_create_infos.len() {
+ debug_utils_messenger_create_infos[i - 1].p_next =
+ &debug_utils_messenger_create_infos[i] as *const _ as *const _;
+ }
+
+ if let Some(info) = debug_utils_messenger_create_infos.first() {
+ create_info_vk.p_next = info as *const _ as *const _;
+ }
+
+ // Creating the Vulkan instance.
+ let handle = {
+ let mut output = MaybeUninit::uninit();
+ let fns = library.fns();
+ (fns.v1_0.create_instance)(&create_info_vk, ptr::null(), output.as_mut_ptr())
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ // Loading the function pointers of the newly-created instance.
+ let fns = {
+ InstanceFunctions::load(|name| {
+ library
+ .get_instance_proc_addr(handle, name.as_ptr())
+ .map_or(ptr::null(), |func| func as _)
+ })
+ };
+
+ Ok(Arc::new(Instance {
+ handle,
+ fns,
+ id: Self::next_id(),
+ api_version,
+ enabled_extensions,
+ enabled_layers,
+ library,
+ max_api_version,
+ _user_callbacks: user_callbacks,
+ }))
+ }
+
+ /// Returns the Vulkan library used to create this instance.
+ #[inline]
+ pub fn library(&self) -> &Arc<VulkanLibrary> {
+ &self.library
+ }
+
+ /// Returns the Vulkan version supported by the instance.
+ ///
+ /// This is the lower of the
+ /// [driver's supported version](crate::VulkanLibrary::api_version) and
+ /// [`max_api_version`](Instance::max_api_version).
+ #[inline]
+ pub fn api_version(&self) -> Version {
+ self.api_version
+ }
+
+ /// Returns the maximum Vulkan version that was specified when creating the instance.
+ #[inline]
+ pub fn max_api_version(&self) -> Version {
+ self.max_api_version
+ }
+
+ /// Returns pointers to the raw Vulkan functions of the instance.
+ #[inline]
+ pub fn fns(&self) -> &InstanceFunctions {
+ &self.fns
+ }
+
+ /// Returns the extensions that have been enabled on the instance.
+ #[inline]
+ pub fn enabled_extensions(&self) -> &InstanceExtensions {
+ &self.enabled_extensions
+ }
+
+ /// Returns the layers that have been enabled on the instance.
+ #[inline]
+ pub fn enabled_layers(&self) -> &[String] {
+ &self.enabled_layers
+ }
+
+ /// Returns an iterator that enumerates the physical devices available.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use vulkano::{
+ /// # instance::{Instance, InstanceExtensions},
+ /// # Version, VulkanLibrary,
+ /// # };
+ ///
+ /// # let library = VulkanLibrary::new().unwrap();
+ /// # let instance = Instance::new(library, Default::default()).unwrap();
+ /// for physical_device in instance.enumerate_physical_devices().unwrap() {
+ /// println!("Available device: {}", physical_device.properties().device_name);
+ /// }
+ /// ```
+ pub fn enumerate_physical_devices(
+ self: &Arc<Self>,
+ ) -> Result<impl ExactSizeIterator<Item = Arc<PhysicalDevice>>, VulkanError> {
+ let fns = self.fns();
+
+ unsafe {
+ let handles = loop {
+ let mut count = 0;
+ (fns.v1_0.enumerate_physical_devices)(self.handle, &mut count, ptr::null_mut())
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut handles = Vec::with_capacity(count as usize);
+ let result = (fns.v1_0.enumerate_physical_devices)(
+ self.handle,
+ &mut count,
+ handles.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ handles.set_len(count as usize);
+ break handles;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err)),
+ }
+ };
+
+ let physical_devices: SmallVec<[_; 4]> = handles
+ .into_iter()
+ .map(|handle| PhysicalDevice::from_handle(self.clone(), handle))
+ .collect::<Result<_, _>>()?;
+
+ Ok(physical_devices.into_iter())
+ }
+ }
+}
+
+impl Drop for Instance {
+ #[inline]
+ fn drop(&mut self) {
+ let fns = self.fns();
+
+ unsafe {
+ (fns.v1_0.destroy_instance)(self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for Instance {
+ type Handle = ash::vk::Instance;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+impl_id_counter!(Instance);
+
+impl Debug for Instance {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ handle,
+ fns,
+ id: _,
+ api_version,
+ enabled_extensions,
+ enabled_layers,
+ library: function_pointers,
+ max_api_version,
+ _user_callbacks: _,
+ } = self;
+
+ f.debug_struct("Instance")
+ .field("handle", handle)
+ .field("fns", fns)
+ .field("api_version", api_version)
+ .field("enabled_extensions", enabled_extensions)
+ .field("enabled_layers", enabled_layers)
+ .field("function_pointers", function_pointers)
+ .field("max_api_version", max_api_version)
+ .finish_non_exhaustive()
+ }
+}
+
+/// Parameters to create a new `Instance`.
+#[derive(Debug)]
+pub struct InstanceCreateInfo {
+ /// A string of your choice stating the name of your application.
+ ///
+ /// The default value is `None`.
+ pub application_name: Option<String>,
+
+ /// A version number of your choice specifying the version of your application.
+ ///
+ /// The default value is zero.
+ pub application_version: Version,
+
+ /// The extensions to enable on the instance.
+ ///
+ /// The default value is [`InstanceExtensions::empty()`].
+ pub enabled_extensions: InstanceExtensions,
+
+ /// The layers to enable on the instance.
+ ///
+ /// The default value is empty.
+ pub enabled_layers: Vec<String>,
+
+ /// A string of your choice stating the name of the engine used to power the application.
+ pub engine_name: Option<String>,
+
+ /// A version number of your choice specifying the version of the engine used to power the
+ /// application.
+ ///
+ /// The default value is zero.
+ pub engine_version: Version,
+
+ /// The highest Vulkan API version that the application will use with the instance.
+ ///
+ /// Usually, you will want to leave this at the default.
+ ///
+ /// The default value is [`Version::HEADER_VERSION`], but if the
+ /// supported instance version is 1.0, then it will be 1.0.
+ pub max_api_version: Option<Version>,
+
+ /// Include [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices when enumerating physical devices.
+ ///
+ /// If you enable this flag, you must ensure that your program is prepared to handle the
+ /// non-conformant aspects of these devices.
+ ///
+ /// If this flag is not enabled, and there are no fully-conformant devices on the system, then
+ /// [`Instance::new`] will return an `IncompatibleDriver` error.
+ ///
+ /// The default value is `false`.
+ ///
+ /// # Notes
+ ///
+ /// If this flag is enabled, and the
+ /// [`khr_portability_enumeration`](crate::instance::InstanceExtensions::khr_portability_enumeration)
+ /// extension is supported, it will be enabled automatically when creating the instance.
+ /// If the extension is not supported, this flag will be ignored.
+ pub enumerate_portability: bool,
+
+ /// Features of the validation layer to enable.
+ ///
+ /// If not empty, the
+ /// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)
+ /// extension must be enabled on the instance.
+ pub enabled_validation_features: Vec<ValidationFeatureEnable>,
+
+ /// Features of the validation layer to disable.
+ ///
+ /// If not empty, the
+ /// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)
+ /// extension must be enabled on the instance.
+ pub disabled_validation_features: Vec<ValidationFeatureDisable>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for InstanceCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ application_name: None,
+ application_version: Version::major_minor(0, 0),
+ enabled_extensions: InstanceExtensions::empty(),
+ enabled_layers: Vec::new(),
+ engine_name: None,
+ engine_version: Version::major_minor(0, 0),
+ max_api_version: None,
+ enumerate_portability: false,
+ enabled_validation_features: Vec::new(),
+ disabled_validation_features: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl InstanceCreateInfo {
+ /// Returns an `InstanceCreateInfo` with the `application_name` and `application_version` set
+ /// from information in your crate's Cargo.toml file.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the required environment variables are missing, which happens if the project
+ /// wasn't built by Cargo.
+ #[inline]
+ pub fn application_from_cargo_toml() -> Self {
+ Self {
+ application_name: Some("vulkano".to_owned()),
+ application_version: Version {
+ major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
+ minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
+ patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
+ },
+ ..Default::default()
+ }
+ }
+}
+
+/// Error that can happen when creating an instance.
+#[derive(Clone, Debug)]
+pub enum InstanceCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// Failed to initialize for an implementation-specific reason.
+ InitializationFailed,
+
+ /// One of the requested layers is missing.
+ LayerNotPresent,
+
+ /// One of the requested extensions is not supported by the implementation.
+ ExtensionNotPresent,
+
+ /// The version requested is not supported by the implementation.
+ IncompatibleDriver,
+
+ /// A restriction for an extension was not met.
+ ExtensionRestrictionNotMet(ExtensionRestrictionError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
+
+impl Error for InstanceCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for InstanceCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::InitializationFailed => write!(f, "initialization failed"),
+ Self::LayerNotPresent => write!(f, "layer not present"),
+ Self::ExtensionNotPresent => write!(f, "extension not present"),
+ Self::IncompatibleDriver => write!(f, "incompatible driver"),
+ Self::ExtensionRestrictionNotMet(err) => Display::fmt(err, f),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ }
+ }
+}
+
+impl From<OomError> for InstanceCreationError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
+ }
+}
+
+impl From<ExtensionRestrictionError> for InstanceCreationError {
+ fn from(err: ExtensionRestrictionError) -> Self {
+ Self::ExtensionRestrictionNotMet(err)
+ }
+}
+
+impl From<VulkanError> for InstanceCreationError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ VulkanError::InitializationFailed => Self::InitializationFailed,
+ VulkanError::LayerNotPresent => Self::LayerNotPresent,
+ VulkanError::ExtensionNotPresent => Self::ExtensionNotPresent,
+ VulkanError::IncompatibleDriver => Self::IncompatibleDriver,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+
+ #[test]
+ fn create_instance() {
+ let _ = instance!();
+ }
+}