aboutsummaryrefslogtreecommitdiff
path: root/src/instance/instance.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/instance/instance.rs')
-rw-r--r--src/instance/instance.rs693
1 files changed, 0 insertions, 693 deletions
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());
- }
-}