use self::debug::{
DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo, ValidationFeatureDisable,
ValidationFeatureEnable,
};
pub use self::layers::LayerProperties;
use crate::{
cache::WeakArcOnceCache,
device::physical::{
PhysicalDevice, PhysicalDeviceGroupProperties, PhysicalDeviceGroupPropertiesRaw,
},
macros::{impl_id_counter, vulkan_bitflags},
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError, VulkanLibrary,
VulkanObject,
};
pub use crate::{fns::InstanceFunctions, version::Version};
use ash::vk::Handle;
use parking_lot::RwLock;
use smallvec::SmallVec;
use std::{
ffi::{c_char, CString},
fmt::{Debug, Error as FmtError, Formatter},
mem::MaybeUninit,
num::NonZeroU64,
ops::Deref,
panic::{RefUnwindSafe, UnwindSafe},
ptr, slice,
sync::Arc,
};
pub mod debug;
mod layers;
include!(concat!(env!("OUT_DIR"), "/instance_extensions.rs"));
pub struct Instance {
handle: ash::vk::Instance,
fns: InstanceFunctions,
id: NonZeroU64,
flags: InstanceCreateFlags,
api_version: Version,
enabled_extensions: InstanceExtensions,
enabled_layers: Vec<String>,
library: Arc<VulkanLibrary>,
max_api_version: Version,
_user_callbacks: Vec<Arc<DebugUtilsMessengerCallback>>,
physical_devices: WeakArcOnceCache<ash::vk::PhysicalDevice, PhysicalDevice>,
physical_device_groups: RwLock<(bool, Vec<PhysicalDeviceGroupPropertiesRaw>)>,
}
impl UnwindSafe for Instance {}
impl RefUnwindSafe for Instance {}
impl Instance {
#[inline]
pub fn new(
library: Arc<VulkanLibrary>,
mut create_info: InstanceCreateInfo,
) -> Result<Arc<Instance>, Validated<VulkanError>> {
create_info.max_api_version.get_or_insert_with(|| {
let api_version = library.api_version();
if api_version < Version::V1_1 {
api_version
} else {
Version::HEADER_VERSION
}
});
Self::validate_new(&library, &create_info)?;
Ok(unsafe { Self::new_unchecked(library, create_info) }?)
}
fn validate_new(
library: &VulkanLibrary,
create_info: &InstanceCreateInfo,
) -> Result<(), Box<ValidationError>> {
create_info
.validate(library)
.map_err(|err| err.add_context("create_info"))?;
let &InstanceCreateInfo {
flags: _,
application_name: _,
application_version: _,
engine_name: _,
engine_version: _,
max_api_version,
ref enabled_layers,
ref enabled_extensions,
debug_utils_messengers: _,
enabled_validation_features: _,
disabled_validation_features: _,
_ne,
} = create_info;
let api_version = std::cmp::min(max_api_version.unwrap_or_default(), library.api_version());
let supported_extensions = library
.supported_extensions_with_layers(enabled_layers.iter().map(String::as_str))
.unwrap();
enabled_extensions
.check_requirements(&supported_extensions, api_version)
.map_err(|err| {
Box::new(ValidationError {
context: "create_info.enabled_extensions".into(),
vuids: &["VUID-vkCreateInstance-ppEnabledExtensionNames-01388"],
..ValidationError::from_error(err)
})
})?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn new_unchecked(
library: Arc<VulkanLibrary>,
mut create_info: InstanceCreateInfo,
) -> Result<Arc<Instance>, VulkanError> {
create_info.max_api_version.get_or_insert_with(|| {
let api_version = library.api_version();
if api_version < Version::V1_1 {
api_version
} else {
Version::HEADER_VERSION
}
});
create_info.enabled_extensions.enable_dependencies(
std::cmp::min(
create_info.max_api_version.unwrap_or_default(),
library.api_version(),
),
&library
.supported_extensions_with_layers(
create_info.enabled_layers.iter().map(String::as_str),
)
.unwrap(),
);
if create_info
.flags
.intersects(InstanceCreateFlags::ENUMERATE_PORTABILITY)
{
if library
.supported_extensions_with_layers(
create_info.enabled_layers.iter().map(String::as_str),
)?
.khr_portability_enumeration
{
create_info.enabled_extensions.khr_portability_enumeration = true;
} else {
create_info.flags -= InstanceCreateFlags::ENUMERATE_PORTABILITY;
}
}
let create_info_fields2_vk = create_info.to_vk_fields2();
let create_info_fields1_vk = create_info.to_vk_fields1(&create_info_fields2_vk);
let mut create_info_extensions_vk = create_info.to_vk_extensions(&create_info_fields1_vk);
let create_info_vk =
create_info.to_vk(&create_info_fields1_vk, &mut create_info_extensions_vk);
let handle = {
let mut output = MaybeUninit::uninit();
let fns = library.fns();
unsafe {
(fns.v1_0.create_instance)(&create_info_vk, ptr::null(), output.as_mut_ptr())
}
.result()
.map_err(VulkanError::from)?;
unsafe { output.assume_init() }
};
Ok(unsafe { Self::from_handle(library, handle, create_info) })
}
pub unsafe fn from_handle(
library: Arc<VulkanLibrary>,
handle: ash::vk::Instance,
mut create_info: InstanceCreateInfo,
) -> Arc<Self> {
create_info.max_api_version.get_or_insert_with(|| {
let api_version = library.api_version();
if api_version < Version::V1_1 {
api_version
} else {
Version::HEADER_VERSION
}
});
let InstanceCreateInfo {
flags,
application_name: _,
application_version: _,
engine_name: _,
engine_version: _,
max_api_version,
enabled_layers,
enabled_extensions,
debug_utils_messengers,
enabled_validation_features: _,
disabled_validation_features: _,
_ne: _,
} = create_info;
let max_api_version = max_api_version.unwrap();
let api_version = std::cmp::min(max_api_version, library.api_version());
Arc::new(Instance {
handle,
fns: InstanceFunctions::load(|name| {
unsafe { library.get_instance_proc_addr(handle, name.as_ptr()) }
.map_or(ptr::null(), |func| func as _)
}),
id: Self::next_id(),
flags,
api_version,
enabled_extensions,
enabled_layers,
library,
max_api_version,
_user_callbacks: debug_utils_messengers
.into_iter()
.map(|m| m.user_callback)
.collect(),
physical_devices: WeakArcOnceCache::new(),
physical_device_groups: RwLock::new((false, Vec::new())),
})
}
#[inline]
pub fn library(&self) -> &Arc<VulkanLibrary> {
&self.library
}
#[inline]
pub fn flags(&self) -> InstanceCreateFlags {
self.flags
}
#[inline]
pub fn api_version(&self) -> Version {
self.api_version
}
#[inline]
pub fn max_api_version(&self) -> Version {
self.max_api_version
}
#[inline]
pub fn fns(&self) -> &InstanceFunctions {
&self.fns
}
#[inline]
pub fn enabled_extensions(&self) -> &InstanceExtensions {
&self.enabled_extensions
}
#[inline]
pub fn enabled_layers(&self) -> &[String] {
&self.enabled_layers
}
pub fn enumerate_physical_devices(
self: &Arc<Self>,
) -> Result<impl ExactSizeIterator<Item = Arc<PhysicalDevice>>, VulkanError> {
let fns = self.fns();
let handles = loop {
let mut count = 0;
unsafe {
(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 = unsafe {
(fns.v1_0.enumerate_physical_devices)(self.handle, &mut count, handles.as_mut_ptr())
};
match result {
ash::vk::Result::SUCCESS => {
unsafe { 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| {
self.physical_devices
.get_or_try_insert(handle, |&handle| unsafe {
PhysicalDevice::from_handle(self.clone(), handle)
})
})
.collect::<Result<_, _>>()?;
Ok(physical_devices.into_iter())
}
#[inline]
pub fn enumerate_physical_device_groups(
self: &Arc<Self>,
) -> Result<impl ExactSizeIterator<Item = PhysicalDeviceGroupProperties>, Validated<VulkanError>>
{
self.validate_enumerate_physical_device_groups()?;
Ok(unsafe { self.enumerate_physical_device_groups_unchecked() }?)
}
fn validate_enumerate_physical_device_groups(&self) -> Result<(), Box<ValidationError>> {
if !(self.api_version() >= Version::V1_1
|| self.enabled_extensions().khr_device_group_creation)
{
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[
RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]),
RequiresAllOf(&[Requires::InstanceExtension("khr_device_group_creation")]),
]),
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn enumerate_physical_device_groups_unchecked(
self: &Arc<Self>,
) -> Result<impl ExactSizeIterator<Item = PhysicalDeviceGroupProperties>, VulkanError> {
let fns = self.fns();
let enumerate_physical_device_groups = if self.api_version() >= Version::V1_1 {
fns.v1_1.enumerate_physical_device_groups
} else {
fns.khr_device_group_creation
.enumerate_physical_device_groups_khr
};
let properties_vk = loop {
let mut count = 0;
unsafe { enumerate_physical_device_groups(self.handle, &mut count, ptr::null_mut()) }
.result()
.map_err(VulkanError::from)?;
let mut properties = Vec::with_capacity(count as usize);
let result = unsafe {
enumerate_physical_device_groups(self.handle, &mut count, properties.as_mut_ptr())
};
match result {
ash::vk::Result::SUCCESS => {
unsafe { properties.set_len(count as usize) };
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
};
let mut properties: SmallVec<[_; 4]> = SmallVec::with_capacity(properties_vk.len());
let mut properties_raw: Vec<_> = Vec::with_capacity(properties_vk.len());
for properties_vk in properties_vk {
let &ash::vk::PhysicalDeviceGroupProperties {
physical_device_count,
physical_devices,
subset_allocation,
..
} = &properties_vk;
properties.push(PhysicalDeviceGroupProperties {
physical_devices: physical_devices[..physical_device_count as usize]
.iter()
.map(|&handle| {
self.physical_devices
.get_or_try_insert(handle, |&handle| unsafe {
PhysicalDevice::from_handle(self.clone(), handle)
})
})
.collect::<Result<_, _>>()?,
subset_allocation: subset_allocation != ash::vk::FALSE,
});
properties_raw.push(PhysicalDeviceGroupPropertiesRaw {
physical_device_count,
physical_devices,
subset_allocation,
});
}
*self.physical_device_groups.write() = (true, properties_raw);
Ok(properties.into_iter())
}
pub fn is_same_device_group<'a>(
self: &Arc<Self>,
physical_devices: impl IntoIterator<Item = &'a PhysicalDevice>,
) -> bool {
let mut physical_devices = physical_devices.into_iter();
let first = match physical_devices.next() {
Some(x) => x,
None => return false,
};
if first.instance() != self {
return false;
}
let lock = {
let lock = self.physical_device_groups.read();
if lock.0 {
lock
} else {
drop(lock);
if self.enumerate_physical_device_groups().is_err() {
return false;
}
self.physical_device_groups.read()
}
};
lock.1
.iter()
.find_map(|properties_raw| {
let group = &properties_raw.physical_devices
[..properties_raw.physical_device_count as usize];
group.contains(&first.handle()).then_some(group)
})
.is_some_and(|group| {
physical_devices.all(|physical_device| {
physical_device.instance() == self && group.contains(&physical_device.handle())
})
})
}
}
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,
flags,
api_version,
enabled_extensions,
enabled_layers,
library,
max_api_version,
_user_callbacks: _,
physical_devices: _,
physical_device_groups: _,
} = self;
f.debug_struct("Instance")
.field("handle", handle)
.field("fns", fns)
.field("id", id)
.field("flags", flags)
.field("api_version", api_version)
.field("enabled_extensions", enabled_extensions)
.field("enabled_layers", enabled_layers)
.field("library", library)
.field("max_api_version", max_api_version)
.finish_non_exhaustive()
}
}
#[derive(Debug)]
pub struct InstanceCreateInfo {
pub flags: InstanceCreateFlags,
pub application_name: Option<String>,
pub application_version: Version,
pub engine_name: Option<String>,
pub engine_version: Version,
pub max_api_version: Option<Version>,
pub enabled_layers: Vec<String>,
pub enabled_extensions: InstanceExtensions,
pub debug_utils_messengers: Vec<DebugUtilsMessengerCreateInfo>,
pub enabled_validation_features: Vec<ValidationFeatureEnable>,
pub disabled_validation_features: Vec<ValidationFeatureDisable>,
pub _ne: crate::NonExhaustive,
}
impl Default for InstanceCreateInfo {
#[inline]
fn default() -> Self {
Self {
flags: InstanceCreateFlags::empty(),
application_name: None,
application_version: Version::major_minor(0, 0),
engine_name: None,
engine_version: Version::major_minor(0, 0),
max_api_version: None,
enabled_layers: Vec::new(),
enabled_extensions: InstanceExtensions::empty(),
debug_utils_messengers: Vec::new(),
enabled_validation_features: Vec::new(),
disabled_validation_features: Vec::new(),
_ne: crate::NonExhaustive(()),
}
}
}
impl InstanceCreateInfo {
#[inline]
pub fn application_from_cargo_toml() -> Self {
Self {
application_name: Some(env!("CARGO_PKG_NAME").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()
}
}
pub(crate) fn validate(&self, library: &VulkanLibrary) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
application_name: _,
application_version: _,
engine_name: _,
engine_version: _,
max_api_version,
enabled_layers: _,
ref enabled_extensions,
ref debug_utils_messengers,
ref enabled_validation_features,
ref disabled_validation_features,
_ne: _,
} = self;
let max_api_version = max_api_version.unwrap_or_default();
let api_version = std::cmp::min(max_api_version, library.api_version());
if max_api_version < Version::V1_0 {
return Err(Box::new(ValidationError {
context: "max_api_version".into(),
problem: "is less than 1.0".into(),
vuids: &["VUID-VkApplicationInfo-apiVersion-04010"],
..Default::default()
}));
}
flags
.validate_instance_raw(api_version, enabled_extensions)
.map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkInstanceCreateInfo-flags-parameter"])
})?;
if !debug_utils_messengers.is_empty() {
if !enabled_extensions.ext_debug_utils {
return Err(Box::new(ValidationError {
context: "debug_utils_messengers".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::InstanceExtension("ext_debug_utils"),
])]),
vuids: &["VUID-VkInstanceCreateInfo-pNext-04926"],
}));
}
for (index, messenger_create_info) in debug_utils_messengers.iter().enumerate() {
messenger_create_info
.validate_raw(api_version, enabled_extensions)
.map_err(|err| err.add_context(format!("debug_utils_messengers[{}]", index)))?;
}
}
if !enabled_validation_features.is_empty() {
if !enabled_extensions.ext_validation_features {
return Err(Box::new(ValidationError {
context: "enabled_validation_features".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::InstanceExtension("ext_validation_features"),
])]),
..Default::default()
}));
}
for (index, enabled) in enabled_validation_features.iter().enumerate() {
enabled
.validate_instance_raw(api_version, enabled_extensions)
.map_err(|err| {
err.add_context(format!("enabled_validation_features[{}]", index))
.set_vuids(&[
"VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-parameter",
])
})?;
}
if enabled_validation_features
.contains(&ValidationFeatureEnable::GpuAssistedReserveBindingSlot)
&& !enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted)
{
return Err(Box::new(ValidationError {
context: "enabled_validation_features".into(),
problem: "contains `ValidationFeatureEnable::GpuAssistedReserveBindingSlot`, \
but does not also contain \
`ValidationFeatureEnable::GpuAssisted`"
.into(),
vuids: &["VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02967"],
..Default::default()
}));
}
if enabled_validation_features.contains(&ValidationFeatureEnable::DebugPrintf)
&& enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted)
{
return Err(Box::new(ValidationError {
context: "enabled_validation_features".into(),
problem: "contains both `ValidationFeatureEnable::DebugPrintf` and \
`ValidationFeatureEnable::GpuAssisted`"
.into(),
vuids: &["VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02968"],
..Default::default()
}));
}
}
if !disabled_validation_features.is_empty() {
if !enabled_extensions.ext_validation_features {
return Err(Box::new(ValidationError {
context: "disabled_validation_features".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::InstanceExtension("ext_validation_features"),
])]),
..Default::default()
}));
}
for (index, disabled) in disabled_validation_features.iter().enumerate() {
disabled
.validate_instance_raw(api_version, enabled_extensions)
.map_err(|err| {
err.add_context(format!("disabled_validation_features[{}]", index)).set_vuids(
&[
"VUID-VkValidationFeaturesEXT-pDisabledValidationFeatures-parameter",
],
)
})?;
}
}
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
fields1_vk: &'a InstanceCreateInfoFields1Vk<'_>,
extensions_vk: &'a mut InstanceCreateInfoExtensionsVk<'_>,
) -> ash::vk::InstanceCreateInfo<'a> {
let &Self {
flags,
application_name: _,
application_version: _,
engine_name: _,
engine_version: _,
max_api_version: _,
enabled_layers: _,
enabled_extensions: _,
debug_utils_messengers: _,
enabled_validation_features: _,
disabled_validation_features: _,
_ne: _,
} = self;
let InstanceCreateInfoFields1Vk {
application_info_vk,
enabled_layer_names_vk,
enabled_extension_names_vk,
enable_validation_features_vk: _,
disable_validation_features_vk: _,
} = fields1_vk;
let mut val_vk = ash::vk::InstanceCreateInfo::default()
.flags(flags.into())
.application_info(application_info_vk)
.enabled_layer_names(enabled_layer_names_vk)
.enabled_extension_names(enabled_extension_names_vk);
let InstanceCreateInfoExtensionsVk {
debug_utils_messengers_vk,
validation_features_vk,
} = extensions_vk;
for next in debug_utils_messengers_vk.iter_mut().rev() {
val_vk = val_vk.push_next(next);
}
if let Some(next) = validation_features_vk {
val_vk = val_vk.push_next(next);
}
val_vk
}
pub(crate) fn to_vk_extensions<'a>(
&self,
fields1_vk: &'a InstanceCreateInfoFields1Vk<'_>,
) -> InstanceCreateInfoExtensionsVk<'a> {
let InstanceCreateInfoFields1Vk {
application_info_vk: _,
enabled_layer_names_vk: _,
enabled_extension_names_vk: _,
enable_validation_features_vk,
disable_validation_features_vk,
} = fields1_vk;
let validation_features_vk = (!enable_validation_features_vk.is_empty()
|| !disable_validation_features_vk.is_empty())
.then(|| {
ash::vk::ValidationFeaturesEXT::default()
.enabled_validation_features(enable_validation_features_vk)
.disabled_validation_features(disable_validation_features_vk)
});
let debug_utils_messengers_vk: Vec<_> = self
.debug_utils_messengers
.iter()
.map(DebugUtilsMessengerCreateInfo::to_vk)
.collect();
InstanceCreateInfoExtensionsVk {
debug_utils_messengers_vk,
validation_features_vk,
}
}
pub(crate) fn to_vk_fields1<'a>(
&self,
fields2_vk: &'a InstanceCreateInfoFields2Vk,
) -> InstanceCreateInfoFields1Vk<'a> {
let &Self {
flags: _,
application_name: _,
application_version,
engine_name: _,
engine_version,
max_api_version,
enabled_layers: _,
enabled_extensions: _,
debug_utils_messengers: _,
ref enabled_validation_features,
ref disabled_validation_features,
_ne: _,
} = self;
let InstanceCreateInfoFields2Vk {
application_name_vk,
engine_name_vk,
enabled_layers_vk,
enabled_extensions_vk,
} = fields2_vk;
let mut application_info_vk = ash::vk::ApplicationInfo::default()
.application_version(
application_version
.try_into()
.expect("Version out of range"),
)
.engine_version(engine_version.try_into().expect("Version out of range"))
.api_version(
max_api_version
.unwrap()
.try_into()
.expect("Version out of range"),
);
if let Some(application_name_vk) = application_name_vk {
application_info_vk = application_info_vk.application_name(application_name_vk);
}
if let Some(engine_name_vk) = engine_name_vk {
application_info_vk = application_info_vk.application_name(engine_name_vk);
}
let enabled_layer_names_vk = enabled_layers_vk
.iter()
.map(|layer| layer.as_ptr())
.collect();
let enabled_extension_names_vk = enabled_extensions_vk
.iter()
.map(|extension| extension.as_ptr())
.collect();
let enable_validation_features_vk = enabled_validation_features
.iter()
.copied()
.map(Into::into)
.collect();
let disable_validation_features_vk = disabled_validation_features
.iter()
.copied()
.map(Into::into)
.collect();
InstanceCreateInfoFields1Vk {
application_info_vk,
enabled_layer_names_vk,
enabled_extension_names_vk,
enable_validation_features_vk,
disable_validation_features_vk,
}
}
pub(crate) fn to_vk_fields2(&self) -> InstanceCreateInfoFields2Vk {
let &Self {
flags: _,
ref application_name,
application_version: _,
ref engine_name,
engine_version: _,
max_api_version: _,
ref enabled_layers,
ref enabled_extensions,
debug_utils_messengers: _,
enabled_validation_features: _,
disabled_validation_features: _,
_ne: _,
} = self;
let application_name_vk = application_name
.as_ref()
.map(|name| CString::new(name.clone()).unwrap());
let engine_name_vk = engine_name
.as_ref()
.map(|name| CString::new(name.clone()).unwrap());
let enabled_layers_vk: Vec<CString> = enabled_layers
.iter()
.map(|name| CString::new(name.clone()).unwrap())
.collect();
let enabled_extensions_vk: Vec<CString> = enabled_extensions.into();
InstanceCreateInfoFields2Vk {
application_name_vk,
engine_name_vk,
enabled_layers_vk,
enabled_extensions_vk,
}
}
}
pub(crate) struct InstanceCreateInfoExtensionsVk<'a> {
pub(crate) debug_utils_messengers_vk: Vec<ash::vk::DebugUtilsMessengerCreateInfoEXT<'a>>,
pub(crate) validation_features_vk: Option<ash::vk::ValidationFeaturesEXT<'a>>,
}
pub(crate) struct InstanceCreateInfoFields1Vk<'a> {
pub(crate) application_info_vk: ash::vk::ApplicationInfo<'a>,
pub(crate) enabled_layer_names_vk: SmallVec<[*const c_char; 2]>,
pub(crate) enabled_extension_names_vk: SmallVec<[*const c_char; 2]>,
pub(crate) enable_validation_features_vk: SmallVec<[ash::vk::ValidationFeatureEnableEXT; 5]>,
pub(crate) disable_validation_features_vk: SmallVec<[ash::vk::ValidationFeatureDisableEXT; 5]>,
}
pub(crate) struct InstanceCreateInfoFields2Vk {
pub(crate) application_name_vk: Option<CString>,
pub(crate) engine_name_vk: Option<CString>,
pub(crate) enabled_layers_vk: Vec<CString>,
pub(crate) enabled_extensions_vk: Vec<CString>,
}
vulkan_bitflags! {
#[non_exhaustive]
InstanceCreateFlags = InstanceCreateFlags(u32);
ENUMERATE_PORTABILITY = ENUMERATE_PORTABILITY_KHR,
}
pub unsafe trait InstanceOwned {
fn instance(&self) -> &Arc<Instance>;
}
unsafe impl<T> InstanceOwned for T
where
T: Deref,
T::Target: InstanceOwned,
{
fn instance(&self) -> &Arc<Instance> {
(**self).instance()
}
}
#[derive(PartialEq, Eq, Hash)]
#[repr(transparent)]
pub(crate) struct InstanceOwnedDebugWrapper<T>(pub(crate) T);
impl<T> InstanceOwnedDebugWrapper<T> {
pub fn cast_slice_inner(slice: &[Self]) -> &[T] {
unsafe { slice::from_raw_parts(<*const _>::cast(slice), slice.len()) }
}
}
impl<T> Debug for InstanceOwnedDebugWrapper<T>
where
T: VulkanObject + InstanceOwned,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
f,
"0x{:x} (instance: 0x{:x})",
self.handle().as_raw(),
self.instance().handle().as_raw(),
)
}
}
impl<T> Deref for InstanceOwnedDebugWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
mod tests {
use crate::instance::InstanceExtensions;
use std::ffi::CString;
#[test]
fn empty_extensions() {
let i: Vec<CString> = (&InstanceExtensions::empty()).into();
assert!(i.is_empty());
}
#[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);
}
}
}
#[test]
fn create_instance() {
let _ = instance!();
}
}