blob: cfee29512c0c7143944c9a3d351f492548a9ea83 [file] [log] [blame]
// Copyright (c) 2021 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 super::QueueFamilyProperties;
use crate::{
buffer::{ExternalBufferInfo, ExternalBufferProperties},
cache::OnceCache,
device::{properties::Properties, DeviceExtensions, Features, FeaturesFfi, PropertiesFfi},
format::{Format, FormatProperties},
image::{
ImageAspects, ImageFormatInfo, ImageFormatProperties, ImageUsage, SparseImageFormatInfo,
SparseImageFormatProperties,
},
instance::Instance,
macros::{impl_id_counter, vulkan_bitflags, vulkan_enum},
memory::{ExternalMemoryHandleType, MemoryProperties},
swapchain::{
ColorSpace, FullScreenExclusive, PresentMode, Surface, SurfaceApi, SurfaceCapabilities,
SurfaceInfo, SurfaceTransforms,
},
sync::{
fence::{ExternalFenceInfo, ExternalFenceProperties},
semaphore::{ExternalSemaphoreInfo, ExternalSemaphoreProperties},
},
ExtensionProperties, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use bytemuck::cast_slice;
use std::{
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
mem::MaybeUninit,
num::NonZeroU64,
ptr,
sync::Arc,
};
/// Represents one of the available physical devices on this machine.
///
/// # Examples
///
/// ```no_run
/// # use vulkano::{
/// # instance::{Instance, InstanceExtensions},
/// # Version, VulkanLibrary,
/// # };
/// use vulkano::device::physical::PhysicalDevice;
///
/// # let library = VulkanLibrary::new().unwrap();
/// # let instance = Instance::new(library, Default::default()).unwrap();
/// for physical_device in instance.enumerate_physical_devices().unwrap() {
/// print_infos(&physical_device);
/// }
///
/// fn print_infos(dev: &PhysicalDevice) {
/// println!("Name: {}", dev.properties().device_name);
/// }
/// ```
#[derive(Debug)]
pub struct PhysicalDevice {
handle: ash::vk::PhysicalDevice,
instance: Arc<Instance>,
id: NonZeroU64,
// Data queried at `PhysicalDevice` creation.
api_version: Version,
supported_extensions: DeviceExtensions,
supported_features: Features,
properties: Properties,
extension_properties: Vec<ExtensionProperties>,
memory_properties: MemoryProperties,
queue_family_properties: Vec<QueueFamilyProperties>,
// Data queried by the user at runtime, cached for faster lookups.
external_buffer_properties: OnceCache<ExternalBufferInfo, ExternalBufferProperties>,
external_fence_properties: OnceCache<ExternalFenceInfo, ExternalFenceProperties>,
external_semaphore_properties: OnceCache<ExternalSemaphoreInfo, ExternalSemaphoreProperties>,
format_properties: OnceCache<Format, FormatProperties>,
image_format_properties: OnceCache<ImageFormatInfo, Option<ImageFormatProperties>>,
sparse_image_format_properties:
OnceCache<SparseImageFormatInfo, Vec<SparseImageFormatProperties>>,
}
impl PhysicalDevice {
/// Creates a new `PhysicalDevice` from a raw object handle.
///
/// # Safety
///
/// - `handle` must be a valid Vulkan object handle created from `instance`.
pub unsafe fn from_handle(
instance: Arc<Instance>,
handle: ash::vk::PhysicalDevice,
) -> Result<Arc<Self>, VulkanError> {
let api_version = Self::get_api_version(handle, &instance);
let extension_properties = Self::get_extension_properties(handle, &instance)?;
let supported_extensions: DeviceExtensions = extension_properties
.iter()
.map(|property| property.extension_name.as_str())
.collect();
let supported_features;
let properties;
let memory_properties;
let queue_family_properties;
// Get the remaining infos.
// If possible, we use VK_KHR_get_physical_device_properties2.
if api_version >= Version::V1_1
|| instance
.enabled_extensions()
.khr_get_physical_device_properties2
{
supported_features =
Self::get_features2(handle, &instance, api_version, &supported_extensions);
properties =
Self::get_properties2(handle, &instance, api_version, &supported_extensions);
memory_properties = Self::get_memory_properties2(handle, &instance);
queue_family_properties = Self::get_queue_family_properties2(handle, &instance);
} else {
supported_features = Self::get_features(handle, &instance);
properties =
Self::get_properties(handle, &instance, api_version, &supported_extensions);
memory_properties = Self::get_memory_properties(handle, &instance);
queue_family_properties = Self::get_queue_family_properties(handle, &instance);
};
Ok(Arc::new(PhysicalDevice {
handle,
instance,
id: Self::next_id(),
api_version,
supported_extensions,
supported_features,
properties,
extension_properties,
memory_properties,
queue_family_properties,
external_buffer_properties: OnceCache::new(),
external_fence_properties: OnceCache::new(),
external_semaphore_properties: OnceCache::new(),
format_properties: OnceCache::new(),
image_format_properties: OnceCache::new(),
sparse_image_format_properties: OnceCache::new(),
}))
}
unsafe fn get_api_version(handle: ash::vk::PhysicalDevice, instance: &Instance) -> Version {
let fns = instance.fns();
let mut output = MaybeUninit::uninit();
(fns.v1_0.get_physical_device_properties)(handle, output.as_mut_ptr());
let api_version = Version::try_from(output.assume_init().api_version).unwrap();
std::cmp::min(instance.max_api_version(), api_version)
}
unsafe fn get_extension_properties(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
) -> Result<Vec<ExtensionProperties>, VulkanError> {
let fns = instance.fns();
loop {
let mut count = 0;
(fns.v1_0.enumerate_device_extension_properties)(
handle,
ptr::null(),
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut output = Vec::with_capacity(count as usize);
let result = (fns.v1_0.enumerate_device_extension_properties)(
handle,
ptr::null(),
&mut count,
output.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
output.set_len(count as usize);
return Ok(output.into_iter().map(Into::into).collect());
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
}
unsafe fn get_features(handle: ash::vk::PhysicalDevice, instance: &Instance) -> Features {
let mut output = FeaturesFfi::default();
let fns = instance.fns();
(fns.v1_0.get_physical_device_features)(handle, &mut output.head_as_mut().features);
Features::from(&output)
}
unsafe fn get_features2(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
api_version: Version,
supported_extensions: &DeviceExtensions,
) -> Features {
let mut output = FeaturesFfi::default();
output.make_chain(
api_version,
supported_extensions,
instance.enabled_extensions(),
);
let fns = instance.fns();
if instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_features2)(handle, output.head_as_mut());
} else {
(fns.khr_get_physical_device_properties2
.get_physical_device_features2_khr)(handle, output.head_as_mut());
}
Features::from(&output)
}
unsafe fn get_properties(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
api_version: Version,
supported_extensions: &DeviceExtensions,
) -> Properties {
let mut output = PropertiesFfi::default();
output.make_chain(
api_version,
supported_extensions,
instance.enabled_extensions(),
);
let fns = instance.fns();
(fns.v1_0.get_physical_device_properties)(handle, &mut output.head_as_mut().properties);
Properties::from(&output)
}
unsafe fn get_properties2(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
api_version: Version,
supported_extensions: &DeviceExtensions,
) -> Properties {
let mut output = PropertiesFfi::default();
output.make_chain(
api_version,
supported_extensions,
instance.enabled_extensions(),
);
let fns = instance.fns();
if instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_properties2)(handle, output.head_as_mut());
} else {
(fns.khr_get_physical_device_properties2
.get_physical_device_properties2_khr)(handle, output.head_as_mut());
}
Properties::from(&output)
}
unsafe fn get_memory_properties(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
) -> MemoryProperties {
let mut output = MaybeUninit::uninit();
let fns = instance.fns();
(fns.v1_0.get_physical_device_memory_properties)(handle, output.as_mut_ptr());
output.assume_init().into()
}
unsafe fn get_memory_properties2(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
) -> MemoryProperties {
let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
let fns = instance.fns();
if instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_memory_properties2)(handle, &mut output);
} else {
(fns.khr_get_physical_device_properties2
.get_physical_device_memory_properties2_khr)(handle, &mut output);
}
output.memory_properties.into()
}
unsafe fn get_queue_family_properties(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
) -> Vec<QueueFamilyProperties> {
let fns = instance.fns();
let mut num = 0;
(fns.v1_0.get_physical_device_queue_family_properties)(handle, &mut num, ptr::null_mut());
let mut output = Vec::with_capacity(num as usize);
(fns.v1_0.get_physical_device_queue_family_properties)(
handle,
&mut num,
output.as_mut_ptr(),
);
output.set_len(num as usize);
output.into_iter().map(Into::into).collect()
}
unsafe fn get_queue_family_properties2(
handle: ash::vk::PhysicalDevice,
instance: &Instance,
) -> Vec<QueueFamilyProperties> {
let mut num = 0;
let fns = instance.fns();
if instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_queue_family_properties2)(
handle,
&mut num,
ptr::null_mut(),
);
} else {
(fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr)(
handle,
&mut num,
ptr::null_mut(),
);
}
let mut output = vec![ash::vk::QueueFamilyProperties2::default(); num as usize];
if instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_queue_family_properties2)(
handle,
&mut num,
output.as_mut_ptr(),
);
} else {
(fns.khr_get_physical_device_properties2
.get_physical_device_queue_family_properties2_khr)(
handle,
&mut num,
output.as_mut_ptr(),
);
}
output
.into_iter()
.map(|family| family.queue_family_properties.into())
.collect()
}
/// Returns the instance that owns the physical device.
#[inline]
pub fn instance(&self) -> &Arc<Instance> {
&self.instance
}
/// Returns the version of Vulkan supported by the physical device.
///
/// Unlike the `api_version` property, which is the version reported by the device directly,
/// this function returns the version the device can actually support, based on the instance's
/// `max_api_version`.
#[inline]
pub fn api_version(&self) -> Version {
self.api_version
}
/// Returns the properties reported by the physical device.
#[inline]
pub fn properties(&self) -> &Properties {
&self.properties
}
/// Returns the extension properties reported by the physical device.
#[inline]
pub fn extension_properties(&self) -> &[ExtensionProperties] {
&self.extension_properties
}
/// Returns the extensions that are supported by the physical device.
#[inline]
pub fn supported_extensions(&self) -> &DeviceExtensions {
&self.supported_extensions
}
/// Returns the features that are supported by the physical device.
#[inline]
pub fn supported_features(&self) -> &Features {
&self.supported_features
}
/// Returns the memory properties reported by the physical device.
#[inline]
pub fn memory_properties(&self) -> &MemoryProperties {
&self.memory_properties
}
/// Returns the queue family properties reported by the physical device.
#[inline]
pub fn queue_family_properties(&self) -> &[QueueFamilyProperties] {
&self.queue_family_properties
}
/// Queries whether the physical device supports presenting to DirectFB surfaces from queues of
/// the given queue family.
///
/// # Safety
///
/// - `dfb` must be a valid DirectFB `IDirectFB` handle.
#[inline]
pub unsafe fn directfb_presentation_support<D>(
&self,
queue_family_index: u32,
dfb: *const D,
) -> Result<bool, PhysicalDeviceError> {
self.validate_directfb_presentation_support(queue_family_index, dfb)?;
Ok(self.directfb_presentation_support_unchecked(queue_family_index, dfb))
}
fn validate_directfb_presentation_support<D>(
&self,
queue_family_index: u32,
_dfb: *const D,
) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().ext_directfb_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::directfb_presentation_support`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_directfb_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceDirectFBPresentationSupportEXT-queueFamilyIndex-04119
if queue_family_index >= self.queue_family_properties.len() as u32 {
return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count: self.queue_family_properties.len() as u32,
});
}
// VUID-vkGetPhysicalDeviceDirectFBPresentationSupportEXT-dfb-parameter
// Can't validate, therefore unsafe
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn directfb_presentation_support_unchecked<D>(
&self,
queue_family_index: u32,
dfb: *const D,
) -> bool {
let fns = self.instance.fns();
(fns.ext_directfb_surface
.get_physical_device_direct_fb_presentation_support_ext)(
self.handle,
queue_family_index,
dfb as *mut _,
) != 0
}
/// Retrieves the external memory properties supported for buffers with a given configuration.
///
/// Instance API version must be at least 1.1, or the [`khr_external_memory_capabilities`]
/// extension must be enabled on the instance.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// [`khr_external_memory_capabilities`]: crate::instance::InstanceExtensions::khr_external_memory_capabilities
#[inline]
pub fn external_buffer_properties(
&self,
info: ExternalBufferInfo,
) -> Result<ExternalBufferProperties, PhysicalDeviceError> {
self.validate_external_buffer_properties(&info)?;
unsafe { Ok(self.external_buffer_properties_unchecked(info)) }
}
fn validate_external_buffer_properties(
&self,
info: &ExternalBufferInfo,
) -> Result<(), PhysicalDeviceError> {
if !(self.instance.api_version() >= Version::V1_1
|| self
.instance
.enabled_extensions()
.khr_external_memory_capabilities)
{
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::external_buffer_properties`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
instance_extensions: &["khr_external_memory_capabilities"],
..Default::default()
},
});
}
let &ExternalBufferInfo {
handle_type,
usage,
sparse: _,
_ne: _,
} = info;
// VUID-VkPhysicalDeviceExternalBufferInfo-usage-parameter
usage.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceExternalBufferInfo-usage-requiredbitmask
assert!(!usage.is_empty());
// VUID-VkPhysicalDeviceExternalBufferInfo-handleType-parameter
handle_type.validate_physical_device(self)?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn external_buffer_properties_unchecked(
&self,
info: ExternalBufferInfo,
) -> ExternalBufferProperties {
self.external_buffer_properties.get_or_insert(info, |info| {
/* Input */
let &ExternalBufferInfo {
handle_type,
usage,
sparse,
_ne: _,
} = info;
let external_buffer_info = ash::vk::PhysicalDeviceExternalBufferInfo {
flags: sparse.map(Into::into).unwrap_or_default(),
usage: usage.into(),
handle_type: handle_type.into(),
..Default::default()
};
/* Output */
let mut external_buffer_properties = ash::vk::ExternalBufferProperties::default();
/* Call */
let fns = self.instance.fns();
if self.instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_external_buffer_properties)(
self.handle,
&external_buffer_info,
&mut external_buffer_properties,
)
} else {
(fns.khr_external_memory_capabilities
.get_physical_device_external_buffer_properties_khr)(
self.handle,
&external_buffer_info,
&mut external_buffer_properties,
);
}
ExternalBufferProperties {
external_memory_properties: external_buffer_properties
.external_memory_properties
.into(),
}
})
}
/// Retrieves the external handle properties supported for fences with a given
/// configuration.
///
/// The instance API version must be at least 1.1, or the [`khr_external_fence_capabilities`]
/// extension must be enabled on the instance.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// [`khr_external_fence_capabilities`]: crate::instance::InstanceExtensions::khr_external_fence_capabilities
#[inline]
pub fn external_fence_properties(
&self,
info: ExternalFenceInfo,
) -> Result<ExternalFenceProperties, PhysicalDeviceError> {
self.validate_external_fence_properties(&info)?;
unsafe { Ok(self.external_fence_properties_unchecked(info)) }
}
fn validate_external_fence_properties(
&self,
info: &ExternalFenceInfo,
) -> Result<(), PhysicalDeviceError> {
if !(self.instance.api_version() >= Version::V1_1
|| self
.instance
.enabled_extensions()
.khr_external_fence_capabilities)
{
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::external_fence_properties`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
instance_extensions: &["khr_external_fence_capabilities"],
..Default::default()
},
});
}
let &ExternalFenceInfo {
handle_type,
_ne: _,
} = info;
// VUID-VkPhysicalDeviceExternalFenceInfo-handleType-parameter
handle_type.validate_physical_device(self)?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn external_fence_properties_unchecked(
&self,
info: ExternalFenceInfo,
) -> ExternalFenceProperties {
self.external_fence_properties.get_or_insert(info, |info| {
/* Input */
let &ExternalFenceInfo {
handle_type,
_ne: _,
} = info;
let external_fence_info = ash::vk::PhysicalDeviceExternalFenceInfo {
handle_type: handle_type.into(),
..Default::default()
};
/* Output */
let mut external_fence_properties = ash::vk::ExternalFenceProperties::default();
/* Call */
let fns = self.instance.fns();
if self.instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_external_fence_properties)(
self.handle,
&external_fence_info,
&mut external_fence_properties,
)
} else {
(fns.khr_external_fence_capabilities
.get_physical_device_external_fence_properties_khr)(
self.handle,
&external_fence_info,
&mut external_fence_properties,
);
}
ExternalFenceProperties {
exportable: external_fence_properties
.external_fence_features
.intersects(ash::vk::ExternalFenceFeatureFlags::EXPORTABLE),
importable: external_fence_properties
.external_fence_features
.intersects(ash::vk::ExternalFenceFeatureFlags::IMPORTABLE),
export_from_imported_handle_types: external_fence_properties
.export_from_imported_handle_types
.into(),
compatible_handle_types: external_fence_properties.compatible_handle_types.into(),
}
})
}
/// Retrieves the external handle properties supported for semaphores with a given
/// configuration.
///
/// The instance API version must be at least 1.1, or the
/// [`khr_external_semaphore_capabilities`] extension must be enabled on the instance.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// [`khr_external_semaphore_capabilities`]: crate::instance::InstanceExtensions::khr_external_semaphore_capabilities
#[inline]
pub fn external_semaphore_properties(
&self,
info: ExternalSemaphoreInfo,
) -> Result<ExternalSemaphoreProperties, PhysicalDeviceError> {
self.validate_external_semaphore_properties(&info)?;
unsafe { Ok(self.external_semaphore_properties_unchecked(info)) }
}
fn validate_external_semaphore_properties(
&self,
info: &ExternalSemaphoreInfo,
) -> Result<(), PhysicalDeviceError> {
if !(self.instance.api_version() >= Version::V1_1
|| self
.instance
.enabled_extensions()
.khr_external_semaphore_capabilities)
{
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::external_semaphore_properties`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
instance_extensions: &["khr_external_semaphore_capabilities"],
..Default::default()
},
});
}
let &ExternalSemaphoreInfo {
handle_type,
_ne: _,
} = info;
// VUID-VkPhysicalDeviceExternalSemaphoreInfo-handleType-parameter
handle_type.validate_physical_device(self)?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn external_semaphore_properties_unchecked(
&self,
info: ExternalSemaphoreInfo,
) -> ExternalSemaphoreProperties {
self.external_semaphore_properties
.get_or_insert(info, |info| {
/* Input */
let &ExternalSemaphoreInfo {
handle_type,
_ne: _,
} = info;
let external_semaphore_info = ash::vk::PhysicalDeviceExternalSemaphoreInfo {
handle_type: handle_type.into(),
..Default::default()
};
/* Output */
let mut external_semaphore_properties =
ash::vk::ExternalSemaphoreProperties::default();
/* Call */
let fns = self.instance.fns();
if self.instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_external_semaphore_properties)(
self.handle,
&external_semaphore_info,
&mut external_semaphore_properties,
)
} else {
(fns.khr_external_semaphore_capabilities
.get_physical_device_external_semaphore_properties_khr)(
self.handle,
&external_semaphore_info,
&mut external_semaphore_properties,
);
}
ExternalSemaphoreProperties {
exportable: external_semaphore_properties
.external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::EXPORTABLE),
importable: external_semaphore_properties
.external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::IMPORTABLE),
export_from_imported_handle_types: external_semaphore_properties
.export_from_imported_handle_types
.into(),
compatible_handle_types: external_semaphore_properties
.compatible_handle_types
.into(),
}
})
}
/// Retrieves the properties of a format when used by this physical device.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
#[inline]
pub fn format_properties(
&self,
format: Format,
) -> Result<FormatProperties, PhysicalDeviceError> {
self.validate_format_properties(format)?;
unsafe { Ok(self.format_properties_unchecked(format)) }
}
fn validate_format_properties(&self, format: Format) -> Result<(), PhysicalDeviceError> {
// VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter
format.validate_physical_device(self)?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn format_properties_unchecked(&self, format: Format) -> FormatProperties {
self.format_properties.get_or_insert(format, |&format| {
let mut format_properties2 = ash::vk::FormatProperties2::default();
let mut format_properties3 = if self.api_version() >= Version::V1_3
|| self.supported_extensions().khr_format_feature_flags2
{
Some(ash::vk::FormatProperties3KHR::default())
} else {
None
};
if let Some(next) = format_properties3.as_mut() {
next.p_next = format_properties2.p_next;
format_properties2.p_next = next as *mut _ as *mut _;
}
let fns = self.instance.fns();
if self.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_format_properties2)(
self.handle,
format.into(),
&mut format_properties2,
);
} else if self
.instance
.enabled_extensions()
.khr_get_physical_device_properties2
{
(fns.khr_get_physical_device_properties2
.get_physical_device_format_properties2_khr)(
self.handle,
format.into(),
&mut format_properties2,
);
} else {
(fns.v1_0.get_physical_device_format_properties)(
self.handle(),
format.into(),
&mut format_properties2.format_properties,
);
}
match format_properties3 {
Some(format_properties3) => FormatProperties {
linear_tiling_features: format_properties3.linear_tiling_features.into(),
optimal_tiling_features: format_properties3.optimal_tiling_features.into(),
buffer_features: format_properties3.buffer_features.into(),
_ne: crate::NonExhaustive(()),
},
None => FormatProperties {
linear_tiling_features: format_properties2
.format_properties
.linear_tiling_features
.into(),
optimal_tiling_features: format_properties2
.format_properties
.optimal_tiling_features
.into(),
buffer_features: format_properties2.format_properties.buffer_features.into(),
_ne: crate::NonExhaustive(()),
},
}
})
}
/// Returns the properties supported for images with a given image configuration.
///
/// `Some` is returned if the configuration is supported, `None` if it is not.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// # Panics
///
/// - Panics if `image_format_info.format` is `None`.
#[inline]
pub fn image_format_properties(
&self,
image_format_info: ImageFormatInfo,
) -> Result<Option<ImageFormatProperties>, PhysicalDeviceError> {
self.validate_image_format_properties(&image_format_info)?;
unsafe { Ok(self.image_format_properties_unchecked(image_format_info)?) }
}
// FIXME: Shouldn't this be private?
pub fn validate_image_format_properties(
&self,
image_format_info: &ImageFormatInfo,
) -> Result<(), PhysicalDeviceError> {
let &ImageFormatInfo {
flags: _,
format,
image_type,
tiling,
usage,
mut stencil_usage,
external_memory_handle_type,
image_view_type,
_ne: _,
} = image_format_info;
let format = format.unwrap();
let aspects = format.aspects();
let has_separate_stencil_usage = if stencil_usage.is_empty()
|| !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
{
stencil_usage = usage;
false
} else {
stencil_usage == usage
};
// VUID-VkPhysicalDeviceImageFormatInfo2-format-parameter
format.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceImageFormatInfo2-imageType-parameter
image_type.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceImageFormatInfo2-tiling-parameter
tiling.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceImageFormatInfo2-usage-parameter
usage.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceImageFormatInfo2-usage-requiredbitmask
assert!(!usage.is_empty());
if has_separate_stencil_usage {
if !(self.api_version() >= Version::V1_2
|| self.supported_extensions().ext_separate_stencil_usage)
{
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`image_format_info.stencil_usage` is `Some` and \
`image_format_info.format` has both a depth and a stencil aspect",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_2),
device_extensions: &["ext_separate_stencil_usage"],
..Default::default()
},
});
}
// VUID-VkImageStencilUsageCreateInfo-stencilUsage-parameter
stencil_usage.validate_physical_device(self)?;
// VUID-VkImageStencilUsageCreateInfo-usage-requiredbitmask
assert!(!stencil_usage.is_empty());
}
if let Some(handle_type) = external_memory_handle_type {
if !(self.api_version() >= Version::V1_1
|| self
.instance()
.enabled_extensions()
.khr_external_memory_capabilities)
{
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`image_format_info.external_memory_handle_type` is `Some`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
instance_extensions: &["khr_external_memory_capabilities"],
..Default::default()
},
});
}
// VUID-VkPhysicalDeviceExternalImageFormatInfo-handleType-parameter
handle_type.validate_physical_device(self)?;
}
if let Some(image_view_type) = image_view_type {
if !self.supported_extensions().ext_filter_cubic {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`image_format_info.image_view_type` is `Some`",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_filter_cubic"],
..Default::default()
},
});
}
// VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-imageViewType-parameter
image_view_type.validate_physical_device(self)?;
}
// TODO: VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02313
// Currently there is nothing in Vulkano for for adding a VkImageFormatListCreateInfo.
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn image_format_properties_unchecked(
&self,
mut image_format_info: ImageFormatInfo,
) -> Result<Option<ImageFormatProperties>, VulkanError> {
{
let ImageFormatInfo {
format,
usage,
stencil_usage,
..
} = &mut image_format_info;
let aspects = format.unwrap().aspects();
if stencil_usage.is_empty()
|| !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
{
*stencil_usage = *usage;
}
}
self.image_format_properties
.get_or_try_insert(image_format_info, |image_format_info| {
/* Input */
let &ImageFormatInfo {
flags,
format,
image_type,
tiling,
usage,
stencil_usage,
external_memory_handle_type,
image_view_type,
_ne: _,
} = image_format_info;
let has_separate_stencil_usage = stencil_usage == usage;
let mut info2_vk = ash::vk::PhysicalDeviceImageFormatInfo2 {
format: format.unwrap().into(),
ty: image_type.into(),
tiling: tiling.into(),
usage: usage.into(),
flags: flags.into(),
..Default::default()
};
let mut external_info_vk = None;
let mut image_view_info_vk = None;
let mut stencil_usage_info_vk = None;
if let Some(handle_type) = external_memory_handle_type {
let next =
external_info_vk.insert(ash::vk::PhysicalDeviceExternalImageFormatInfo {
handle_type: handle_type.into(),
..Default::default()
});
next.p_next = info2_vk.p_next;
info2_vk.p_next = next as *const _ as *const _;
}
if let Some(image_view_type) = image_view_type {
let next = image_view_info_vk.insert(
ash::vk::PhysicalDeviceImageViewImageFormatInfoEXT {
image_view_type: image_view_type.into(),
..Default::default()
},
);
next.p_next = info2_vk.p_next as *mut _;
info2_vk.p_next = next as *const _ as *const _;
}
if has_separate_stencil_usage {
let next = stencil_usage_info_vk.insert(ash::vk::ImageStencilUsageCreateInfo {
stencil_usage: stencil_usage.into(),
..Default::default()
});
next.p_next = info2_vk.p_next as *mut _;
info2_vk.p_next = next as *const _ as *const _;
}
/* Output */
let mut properties2_vk = ash::vk::ImageFormatProperties2::default();
let mut external_properties_vk = None;
let mut filter_cubic_image_view_properties_vk = None;
if external_info_vk.is_some() {
let next = external_properties_vk
.insert(ash::vk::ExternalImageFormatProperties::default());
next.p_next = properties2_vk.p_next;
properties2_vk.p_next = next as *mut _ as *mut _;
}
if image_view_info_vk.is_some() {
let next = filter_cubic_image_view_properties_vk
.insert(ash::vk::FilterCubicImageViewImageFormatPropertiesEXT::default());
next.p_next = properties2_vk.p_next;
properties2_vk.p_next = next as *mut _ as *mut _;
}
let result = {
let fns = self.instance.fns();
if self.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_image_format_properties2)(
self.handle,
&info2_vk,
&mut properties2_vk,
)
} else if self
.instance
.enabled_extensions()
.khr_get_physical_device_properties2
{
(fns.khr_get_physical_device_properties2
.get_physical_device_image_format_properties2_khr)(
self.handle,
&info2_vk,
&mut properties2_vk,
)
} else {
// Can't query this, return unsupported
if !info2_vk.p_next.is_null() {
return Ok(None);
}
if let Some(ExternalMemoryHandleType::DmaBuf) = external_memory_handle_type
{
// VUID-vkGetPhysicalDeviceImageFormatProperties-tiling-02248
// VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249
return Ok(None);
}
(fns.v1_0.get_physical_device_image_format_properties)(
self.handle,
info2_vk.format,
info2_vk.ty,
info2_vk.tiling,
info2_vk.usage,
info2_vk.flags,
&mut properties2_vk.image_format_properties,
)
}
.result()
.map_err(VulkanError::from)
};
Ok(match result {
Ok(_) => Some(ImageFormatProperties {
external_memory_properties: external_properties_vk
.map(|properties| properties.external_memory_properties.into())
.unwrap_or_default(),
filter_cubic: filter_cubic_image_view_properties_vk
.map_or(false, |properties| {
properties.filter_cubic != ash::vk::FALSE
}),
filter_cubic_minmax: filter_cubic_image_view_properties_vk
.map_or(false, |properties| {
properties.filter_cubic_minmax != ash::vk::FALSE
}),
..properties2_vk.image_format_properties.into()
}),
Err(VulkanError::FormatNotSupported) => None,
Err(err) => return Err(err),
})
})
}
/// Queries whether the physical device supports presenting to QNX Screen surfaces from queues
/// of the given queue family.
///
/// # Safety
///
/// - `window` must be a valid QNX Screen `_screen_window` handle.
pub unsafe fn qnx_screen_presentation_support<W>(
&self,
queue_family_index: u32,
window: *const W,
) -> Result<bool, PhysicalDeviceError> {
self.validate_qnx_screen_presentation_support(queue_family_index, window)?;
Ok(self.qnx_screen_presentation_support_unchecked(queue_family_index, window))
}
fn validate_qnx_screen_presentation_support<W>(
&self,
queue_family_index: u32,
_window: *const W,
) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().qnx_screen_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::qnx_screen_presentation_support`",
requires_one_of: RequiresOneOf {
instance_extensions: &["qnx_screen_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceScreenPresentationSupportQNX-queueFamilyIndex-04743
if queue_family_index >= self.queue_family_properties.len() as u32 {
return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count: self.queue_family_properties.len() as u32,
});
}
// VUID-vkGetPhysicalDeviceScreenPresentationSupportQNX-window-parameter
// Can't validate, therefore unsafe
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn qnx_screen_presentation_support_unchecked<W>(
&self,
queue_family_index: u32,
window: *const W,
) -> bool {
let fns = self.instance.fns();
(fns.qnx_screen_surface
.get_physical_device_screen_presentation_support_qnx)(
self.handle,
queue_family_index,
window as *mut _,
) != 0
}
/// Returns the properties of sparse images with a given image configuration.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// # Panics
///
/// - Panics if `format_info.format` is `None`.
#[inline]
pub fn sparse_image_format_properties(
&self,
format_info: SparseImageFormatInfo,
) -> Result<Vec<SparseImageFormatProperties>, PhysicalDeviceError> {
self.validate_sparse_image_format_properties(&format_info)?;
unsafe { Ok(self.sparse_image_format_properties_unchecked(format_info)) }
}
fn validate_sparse_image_format_properties(
&self,
format_info: &SparseImageFormatInfo,
) -> Result<(), PhysicalDeviceError> {
let &SparseImageFormatInfo {
format,
image_type,
samples,
usage,
tiling,
_ne: _,
} = format_info;
let format = format.unwrap();
// VUID-VkPhysicalDeviceSparseImageFormatInfo2-format-parameter
format.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceSparseImageFormatInfo2-type-parameter
image_type.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceSparseImageFormatInfo2-samples-parameter
samples.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceSparseImageFormatInfo2-usage-parameter
usage.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceSparseImageFormatInfo2-usage-requiredbitmask
assert!(!usage.is_empty());
// VUID-VkPhysicalDeviceSparseImageFormatInfo2-tiling-parameter
tiling.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceSparseImageFormatInfo2-samples-01095
// TODO:
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn sparse_image_format_properties_unchecked(
&self,
format_info: SparseImageFormatInfo,
) -> Vec<SparseImageFormatProperties> {
self.sparse_image_format_properties
.get_or_insert(format_info, |format_info| {
let &SparseImageFormatInfo {
format,
image_type,
samples,
usage,
tiling,
_ne: _,
} = format_info;
let format_info2 = ash::vk::PhysicalDeviceSparseImageFormatInfo2 {
format: format.unwrap().into(),
ty: image_type.into(),
samples: samples.into(),
usage: usage.into(),
tiling: tiling.into(),
..Default::default()
};
let fns = self.instance.fns();
if self.api_version() >= Version::V1_1
|| self
.instance
.enabled_extensions()
.khr_get_physical_device_properties2
{
let mut count = 0;
if self.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_sparse_image_format_properties2)(
self.handle,
&format_info2,
&mut count,
ptr::null_mut(),
);
} else {
(fns.khr_get_physical_device_properties2
.get_physical_device_sparse_image_format_properties2_khr)(
self.handle,
&format_info2,
&mut count,
ptr::null_mut(),
);
}
let mut sparse_image_format_properties2 =
vec![ash::vk::SparseImageFormatProperties2::default(); count as usize];
if self.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_sparse_image_format_properties2)(
self.handle,
&format_info2,
&mut count,
sparse_image_format_properties2.as_mut_ptr(),
);
} else {
(fns.khr_get_physical_device_properties2
.get_physical_device_sparse_image_format_properties2_khr)(
self.handle,
&format_info2,
&mut count,
sparse_image_format_properties2.as_mut_ptr(),
);
}
sparse_image_format_properties2.set_len(count as usize);
sparse_image_format_properties2
.into_iter()
.map(
|sparse_image_format_properties2| SparseImageFormatProperties {
aspects: sparse_image_format_properties2
.properties
.aspect_mask
.into(),
image_granularity: [
sparse_image_format_properties2
.properties
.image_granularity
.width,
sparse_image_format_properties2
.properties
.image_granularity
.height,
sparse_image_format_properties2
.properties
.image_granularity
.depth,
],
flags: sparse_image_format_properties2.properties.flags.into(),
},
)
.collect()
} else {
let mut count = 0;
(fns.v1_0.get_physical_device_sparse_image_format_properties)(
self.handle,
format_info2.format,
format_info2.ty,
format_info2.samples,
format_info2.usage,
format_info2.tiling,
&mut count,
ptr::null_mut(),
);
let mut sparse_image_format_properties =
vec![ash::vk::SparseImageFormatProperties::default(); count as usize];
(fns.v1_0.get_physical_device_sparse_image_format_properties)(
self.handle,
format_info2.format,
format_info2.ty,
format_info2.samples,
format_info2.usage,
format_info2.tiling,
&mut count,
sparse_image_format_properties.as_mut_ptr(),
);
sparse_image_format_properties.set_len(count as usize);
sparse_image_format_properties
.into_iter()
.map(
|sparse_image_format_properties| SparseImageFormatProperties {
aspects: sparse_image_format_properties.aspect_mask.into(),
image_granularity: [
sparse_image_format_properties.image_granularity.width,
sparse_image_format_properties.image_granularity.height,
sparse_image_format_properties.image_granularity.depth,
],
flags: sparse_image_format_properties.flags.into(),
},
)
.collect()
}
})
}
/// Returns the capabilities that are supported by the physical device for the given surface.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// # Panics
///
/// - Panics if the physical device and the surface don't belong to the same instance.
pub fn surface_capabilities(
&self,
surface: &Surface,
surface_info: SurfaceInfo,
) -> Result<SurfaceCapabilities, PhysicalDeviceError> {
self.validate_surface_capabilities(surface, &surface_info)?;
unsafe { Ok(self.surface_capabilities_unchecked(surface, surface_info)?) }
}
fn validate_surface_capabilities(
&self,
surface: &Surface,
surface_info: &SurfaceInfo,
) -> Result<(), PhysicalDeviceError> {
if !(self
.instance
.enabled_extensions()
.khr_get_surface_capabilities2
|| self.instance.enabled_extensions().khr_surface)
{
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::surface_capabilities`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_get_surface_capabilities2", "khr_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceSurfaceCapabilities2KHR-commonparent
assert_eq!(self.instance(), surface.instance());
// VUID-vkGetPhysicalDeviceSurfaceCapabilities2KHR-pSurfaceInfo-06210
if !(0..self.queue_family_properties.len() as u32).any(|index| unsafe {
self.surface_support_unchecked(index, surface)
.unwrap_or_default()
}) {
return Err(PhysicalDeviceError::SurfaceNotSupported);
}
let &SurfaceInfo {
full_screen_exclusive,
win32_monitor,
_ne: _,
} = surface_info;
if !self.supported_extensions().ext_full_screen_exclusive
&& full_screen_exclusive != FullScreenExclusive::Default
{
return Err(PhysicalDeviceError::NotSupported);
}
// VUID-VkPhysicalDeviceSurfaceInfo2KHR-pNext-02672
if (surface.api() == SurfaceApi::Win32
&& full_screen_exclusive == FullScreenExclusive::ApplicationControlled)
!= win32_monitor.is_some()
{
return Err(PhysicalDeviceError::NotSupported);
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn surface_capabilities_unchecked(
&self,
surface: &Surface,
surface_info: SurfaceInfo,
) -> Result<SurfaceCapabilities, VulkanError> {
/* Input */
let SurfaceInfo {
full_screen_exclusive,
win32_monitor,
_ne: _,
} = surface_info;
let mut info_vk = ash::vk::PhysicalDeviceSurfaceInfo2KHR {
surface: surface.handle(),
..Default::default()
};
let mut full_screen_exclusive_info_vk = None;
let mut full_screen_exclusive_win32_info_vk = None;
if self.supported_extensions().ext_full_screen_exclusive && win32_monitor.is_some() {
let next =
full_screen_exclusive_info_vk.insert(ash::vk::SurfaceFullScreenExclusiveInfoEXT {
full_screen_exclusive: full_screen_exclusive.into(),
..Default::default()
});
next.p_next = info_vk.p_next as *mut _;
info_vk.p_next = next as *const _ as *const _;
}
if let Some(win32_monitor) = win32_monitor {
let next = full_screen_exclusive_win32_info_vk.insert(
ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
hmonitor: win32_monitor.0,
..Default::default()
},
);
next.p_next = info_vk.p_next as *mut _;
info_vk.p_next = next as *const _ as *const _;
}
/* Output */
let mut capabilities_vk = ash::vk::SurfaceCapabilities2KHR::default();
let mut capabilities_full_screen_exclusive_vk = None;
let mut protected_capabilities_vk = None;
if full_screen_exclusive_info_vk.is_some() {
let next = capabilities_full_screen_exclusive_vk
.insert(ash::vk::SurfaceCapabilitiesFullScreenExclusiveEXT::default());
next.p_next = capabilities_vk.p_next as *mut _;
capabilities_vk.p_next = next as *mut _ as *mut _;
}
if self
.instance
.enabled_extensions()
.khr_surface_protected_capabilities
{
let next = protected_capabilities_vk
.insert(ash::vk::SurfaceProtectedCapabilitiesKHR::default());
next.p_next = capabilities_vk.p_next as *mut _;
capabilities_vk.p_next = next as *mut _ as *mut _;
}
let fns = self.instance.fns();
if self
.instance
.enabled_extensions()
.khr_get_surface_capabilities2
{
(fns.khr_get_surface_capabilities2
.get_physical_device_surface_capabilities2_khr)(
self.handle(),
&info_vk,
&mut capabilities_vk,
)
.result()
.map_err(VulkanError::from)?;
} else {
(fns.khr_surface.get_physical_device_surface_capabilities_khr)(
self.handle(),
info_vk.surface,
&mut capabilities_vk.surface_capabilities,
)
.result()
.map_err(VulkanError::from)?;
};
Ok(SurfaceCapabilities {
min_image_count: capabilities_vk.surface_capabilities.min_image_count,
max_image_count: if capabilities_vk.surface_capabilities.max_image_count == 0 {
None
} else {
Some(capabilities_vk.surface_capabilities.max_image_count)
},
current_extent: if capabilities_vk.surface_capabilities.current_extent.width
== 0xffffffff
&& capabilities_vk.surface_capabilities.current_extent.height == 0xffffffff
{
None
} else {
Some([
capabilities_vk.surface_capabilities.current_extent.width,
capabilities_vk.surface_capabilities.current_extent.height,
])
},
min_image_extent: [
capabilities_vk.surface_capabilities.min_image_extent.width,
capabilities_vk.surface_capabilities.min_image_extent.height,
],
max_image_extent: [
capabilities_vk.surface_capabilities.max_image_extent.width,
capabilities_vk.surface_capabilities.max_image_extent.height,
],
max_image_array_layers: capabilities_vk.surface_capabilities.max_image_array_layers,
supported_transforms: capabilities_vk
.surface_capabilities
.supported_transforms
.into(),
current_transform: SurfaceTransforms::from(
capabilities_vk.surface_capabilities.current_transform,
)
.into_iter()
.next()
.unwrap(), // TODO:
supported_composite_alpha: capabilities_vk
.surface_capabilities
.supported_composite_alpha
.into(),
supported_usage_flags: {
let usage =
ImageUsage::from(capabilities_vk.surface_capabilities.supported_usage_flags);
debug_assert!(usage.intersects(ImageUsage::COLOR_ATTACHMENT)); // specs say that this must be true
usage
},
supports_protected: protected_capabilities_vk
.map_or(false, |c| c.supports_protected != 0),
full_screen_exclusive_supported: capabilities_full_screen_exclusive_vk
.map_or(false, |c| c.full_screen_exclusive_supported != 0),
})
}
/// Returns the combinations of format and color space that are supported by the physical device
/// for the given surface.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// # Panics
///
/// - Panics if the physical device and the surface don't belong to the same instance.
pub fn surface_formats(
&self,
surface: &Surface,
surface_info: SurfaceInfo,
) -> Result<Vec<(Format, ColorSpace)>, PhysicalDeviceError> {
self.validate_surface_formats(surface, &surface_info)?;
unsafe { Ok(self.surface_formats_unchecked(surface, surface_info)?) }
}
fn validate_surface_formats(
&self,
surface: &Surface,
surface_info: &SurfaceInfo,
) -> Result<(), PhysicalDeviceError> {
if !(self
.instance
.enabled_extensions()
.khr_get_surface_capabilities2
|| self.instance.enabled_extensions().khr_surface)
{
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::surface_formats`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_get_surface_capabilities2", "khr_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceSurfaceFormats2KHR-commonparent
assert_eq!(self.instance(), surface.instance());
// VUID-vkGetPhysicalDeviceSurfaceFormats2KHR-pSurfaceInfo-06522
if !(0..self.queue_family_properties.len() as u32).any(|index| unsafe {
self.surface_support_unchecked(index, surface)
.unwrap_or_default()
}) {
return Err(PhysicalDeviceError::SurfaceNotSupported);
}
let &SurfaceInfo {
full_screen_exclusive,
win32_monitor,
_ne: _,
} = surface_info;
if self
.instance
.enabled_extensions()
.khr_get_surface_capabilities2
{
if !self.supported_extensions().ext_full_screen_exclusive
&& full_screen_exclusive != FullScreenExclusive::Default
{
return Err(PhysicalDeviceError::NotSupported);
}
// VUID-VkPhysicalDeviceSurfaceInfo2KHR-pNext-02672
if (surface.api() == SurfaceApi::Win32
&& full_screen_exclusive == FullScreenExclusive::ApplicationControlled)
!= win32_monitor.is_some()
{
return Err(PhysicalDeviceError::NotSupported);
}
} else {
if full_screen_exclusive != FullScreenExclusive::Default {
return Err(PhysicalDeviceError::NotSupported);
}
if win32_monitor.is_some() {
return Err(PhysicalDeviceError::NotSupported);
}
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn surface_formats_unchecked(
&self,
surface: &Surface,
surface_info: SurfaceInfo,
) -> Result<Vec<(Format, ColorSpace)>, VulkanError> {
surface.surface_formats.get_or_try_insert(
(self.handle, surface_info),
|(_, surface_info)| {
let &SurfaceInfo {
full_screen_exclusive,
win32_monitor,
_ne: _,
} = surface_info;
let mut surface_full_screen_exclusive_info = (full_screen_exclusive
!= FullScreenExclusive::Default)
.then(|| ash::vk::SurfaceFullScreenExclusiveInfoEXT {
full_screen_exclusive: full_screen_exclusive.into(),
..Default::default()
});
let mut surface_full_screen_exclusive_win32_info =
win32_monitor.map(|win32_monitor| {
ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
hmonitor: win32_monitor.0,
..Default::default()
}
});
let mut surface_info2 = ash::vk::PhysicalDeviceSurfaceInfo2KHR {
surface: surface.handle(),
..Default::default()
};
if let Some(surface_full_screen_exclusive_info) =
surface_full_screen_exclusive_info.as_mut()
{
surface_full_screen_exclusive_info.p_next = surface_info2.p_next as *mut _;
surface_info2.p_next =
surface_full_screen_exclusive_info as *const _ as *const _;
}
if let Some(surface_full_screen_exclusive_win32_info) =
surface_full_screen_exclusive_win32_info.as_mut()
{
surface_full_screen_exclusive_win32_info.p_next =
surface_info2.p_next as *mut _;
surface_info2.p_next =
surface_full_screen_exclusive_win32_info as *const _ as *const _;
}
let fns = self.instance.fns();
if self
.instance
.enabled_extensions()
.khr_get_surface_capabilities2
{
let surface_format2s = loop {
let mut count = 0;
(fns.khr_get_surface_capabilities2
.get_physical_device_surface_formats2_khr)(
self.handle(),
&surface_info2,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut surface_format2s =
vec![ash::vk::SurfaceFormat2KHR::default(); count as usize];
let result = (fns
.khr_get_surface_capabilities2
.get_physical_device_surface_formats2_khr)(
self.handle(),
&surface_info2,
&mut count,
surface_format2s.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
surface_format2s.set_len(count as usize);
break surface_format2s;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
};
Ok(surface_format2s
.into_iter()
.filter_map(|surface_format2| {
(surface_format2.surface_format.format.try_into().ok())
.zip(surface_format2.surface_format.color_space.try_into().ok())
})
.collect())
} else {
let surface_formats = loop {
let mut count = 0;
(fns.khr_surface.get_physical_device_surface_formats_khr)(
self.handle(),
surface.handle(),
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut surface_formats = Vec::with_capacity(count as usize);
let result = (fns.khr_surface.get_physical_device_surface_formats_khr)(
self.handle(),
surface.handle(),
&mut count,
surface_formats.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
surface_formats.set_len(count as usize);
break surface_formats;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
};
Ok(surface_formats
.into_iter()
.filter_map(|surface_format| {
(surface_format.format.try_into().ok())
.zip(surface_format.color_space.try_into().ok())
})
.collect())
}
},
)
}
/// Returns the present modes that are supported by the physical device for the given surface.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
///
/// # Panics
///
/// - Panics if the physical device and the surface don't belong to the same instance.
pub fn surface_present_modes(
&self,
surface: &Surface,
) -> Result<impl Iterator<Item = PresentMode>, PhysicalDeviceError> {
self.validate_surface_present_modes(surface)?;
unsafe { Ok(self.surface_present_modes_unchecked(surface)?) }
}
fn validate_surface_present_modes(&self, surface: &Surface) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().khr_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::surface_present_modes`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceSurfacePresentModesKHR-commonparent
assert_eq!(self.instance(), surface.instance());
// VUID-vkGetPhysicalDeviceSurfacePresentModesKHR-surface-06525
if !(0..self.queue_family_properties.len() as u32).any(|index| unsafe {
self.surface_support_unchecked(index, surface)
.unwrap_or_default()
}) {
return Err(PhysicalDeviceError::SurfaceNotSupported);
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn surface_present_modes_unchecked(
&self,
surface: &Surface,
) -> Result<impl Iterator<Item = PresentMode>, VulkanError> {
surface
.surface_present_modes
.get_or_try_insert(self.handle, |_| {
let fns = self.instance.fns();
let modes = loop {
let mut count = 0;
(fns.khr_surface
.get_physical_device_surface_present_modes_khr)(
self.handle(),
surface.handle(),
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut modes = Vec::with_capacity(count as usize);
let result = (fns
.khr_surface
.get_physical_device_surface_present_modes_khr)(
self.handle(),
surface.handle(),
&mut count,
modes.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
modes.set_len(count as usize);
break modes;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
};
Ok(modes
.into_iter()
.filter_map(|mode_vk| mode_vk.try_into().ok())
.collect())
})
.map(IntoIterator::into_iter)
}
/// Returns whether queues of the given queue family can draw on the given surface.
///
/// The results of this function are cached, so that future calls with the same arguments
/// do not need to make a call to the Vulkan API again.
#[inline]
pub fn surface_support(
&self,
queue_family_index: u32,
surface: &Surface,
) -> Result<bool, PhysicalDeviceError> {
self.validate_surface_support(queue_family_index, surface)?;
unsafe { Ok(self.surface_support_unchecked(queue_family_index, surface)?) }
}
fn validate_surface_support(
&self,
queue_family_index: u32,
_surface: &Surface,
) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().khr_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::surface_support`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceSurfaceSupportKHR-queueFamilyIndex-01269
if queue_family_index >= self.queue_family_properties.len() as u32 {
return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count: self.queue_family_properties.len() as u32,
});
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn surface_support_unchecked(
&self,
queue_family_index: u32,
surface: &Surface,
) -> Result<bool, VulkanError> {
surface
.surface_support
.get_or_try_insert((self.handle, queue_family_index), |_| {
let fns = self.instance.fns();
let mut output = MaybeUninit::uninit();
(fns.khr_surface.get_physical_device_surface_support_khr)(
self.handle,
queue_family_index,
surface.handle(),
output.as_mut_ptr(),
)
.result()
.map_err(VulkanError::from)?;
Ok(output.assume_init() != 0)
})
}
/// Retrieves the properties of tools that are currently active on the physical device.
///
/// These properties may change during runtime, so the result only reflects the current
/// situation and is not cached.
///
/// The physical device API version must be at least 1.3, or the
/// [`ext_tooling_info`](crate::device::DeviceExtensions::ext_tooling_info)
/// extension must be supported by the physical device.
#[inline]
pub fn tool_properties(&self) -> Result<Vec<ToolProperties>, PhysicalDeviceError> {
self.validate_tool_properties()?;
unsafe { Ok(self.tool_properties_unchecked()?) }
}
fn validate_tool_properties(&self) -> Result<(), PhysicalDeviceError> {
if !(self.api_version() >= Version::V1_3 || self.supported_extensions().ext_tooling_info) {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::tooling_properties`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
device_extensions: &["ext_tooling_info"],
..Default::default()
},
});
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn tool_properties_unchecked(&self) -> Result<Vec<ToolProperties>, VulkanError> {
let fns = self.instance.fns();
loop {
let mut count = 0;
if self.api_version() >= Version::V1_3 {
(fns.v1_3.get_physical_device_tool_properties)(
self.handle(),
&mut count,
ptr::null_mut(),
)
} else {
(fns.ext_tooling_info.get_physical_device_tool_properties_ext)(
self.handle(),
&mut count,
ptr::null_mut(),
)
}
.result()
.map_err(VulkanError::from)?;
let mut tool_properties = Vec::with_capacity(count as usize);
let result = if self.api_version() >= Version::V1_3 {
(fns.v1_3.get_physical_device_tool_properties)(
self.handle(),
&mut count,
tool_properties.as_mut_ptr(),
)
} else {
(fns.ext_tooling_info.get_physical_device_tool_properties_ext)(
self.handle(),
&mut count,
tool_properties.as_mut_ptr(),
)
};
match result {
ash::vk::Result::INCOMPLETE => (),
ash::vk::Result::SUCCESS => {
tool_properties.set_len(count as usize);
return Ok(tool_properties
.into_iter()
.map(|tool_properties| ToolProperties {
name: {
let bytes = cast_slice(tool_properties.name.as_slice());
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[0..end]).into()
},
version: {
let bytes = cast_slice(tool_properties.version.as_slice());
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[0..end]).into()
},
purposes: tool_properties.purposes.into(),
description: {
let bytes = cast_slice(tool_properties.description.as_slice());
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[0..end]).into()
},
layer: {
let bytes = cast_slice(tool_properties.layer.as_slice());
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[0..end]).into()
},
})
.collect());
}
err => return Err(VulkanError::from(err)),
}
}
}
/// Queries whether the physical device supports presenting to Wayland surfaces from queues of
/// the given queue family.
///
/// # Safety
///
/// - `display` must be a valid Wayland `wl_display` handle.
pub unsafe fn wayland_presentation_support<D>(
&self,
queue_family_index: u32,
display: *const D,
) -> Result<bool, PhysicalDeviceError> {
self.validate_wayland_presentation_support(queue_family_index, display)?;
Ok(self.wayland_presentation_support_unchecked(queue_family_index, display))
}
fn validate_wayland_presentation_support<D>(
&self,
queue_family_index: u32,
_display: *const D,
) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().khr_wayland_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::wayland_presentation_support`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_wayland_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceWaylandPresentationSupportKHR-queueFamilyIndex-01306
if queue_family_index >= self.queue_family_properties.len() as u32 {
return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count: self.queue_family_properties.len() as u32,
});
}
// VUID-vkGetPhysicalDeviceWaylandPresentationSupportKHR-display-parameter
// Can't validate, therefore unsafe
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn wayland_presentation_support_unchecked<D>(
&self,
queue_family_index: u32,
display: *const D,
) -> bool {
let fns = self.instance.fns();
(fns.khr_wayland_surface
.get_physical_device_wayland_presentation_support_khr)(
self.handle,
queue_family_index,
display as *mut _,
) != 0
}
/// Queries whether the physical device supports presenting to Win32 surfaces from queues of the
/// given queue family.
#[inline]
pub fn win32_presentation_support(
&self,
queue_family_index: u32,
) -> Result<bool, PhysicalDeviceError> {
self.validate_win32_presentation_support(queue_family_index)?;
unsafe { Ok(self.win32_presentation_support_unchecked(queue_family_index)) }
}
fn validate_win32_presentation_support(
&self,
queue_family_index: u32,
) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().khr_win32_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::win32_presentation_support`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_win32_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceWin32PresentationSupportKHR-queueFamilyIndex-01309
if queue_family_index >= self.queue_family_properties.len() as u32 {
return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count: self.queue_family_properties.len() as u32,
});
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn win32_presentation_support_unchecked(&self, queue_family_index: u32) -> bool {
let fns = self.instance.fns();
(fns.khr_win32_surface
.get_physical_device_win32_presentation_support_khr)(
self.handle, queue_family_index
) != 0
}
/// Queries whether the physical device supports presenting to XCB surfaces from queues of the
/// given queue family.
///
/// # Safety
///
/// - `connection` must be a valid X11 `xcb_connection_t` handle.
pub unsafe fn xcb_presentation_support<C>(
&self,
queue_family_index: u32,
connection: *const C,
visual_id: ash::vk::xcb_visualid_t,
) -> Result<bool, PhysicalDeviceError> {
self.validate_xcb_presentation_support(queue_family_index, connection, visual_id)?;
Ok(self.xcb_presentation_support_unchecked(queue_family_index, connection, visual_id))
}
fn validate_xcb_presentation_support<C>(
&self,
queue_family_index: u32,
_connection: *const C,
_visual_id: ash::vk::xcb_visualid_t,
) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().khr_xcb_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::xcb_presentation_support`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_xcb_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceXcbPresentationSupportKHR-queueFamilyIndex-01312
if queue_family_index >= self.queue_family_properties.len() as u32 {
return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count: self.queue_family_properties.len() as u32,
});
}
// VUID-vkGetPhysicalDeviceXcbPresentationSupportKHR-connection-parameter
// Can't validate, therefore unsafe
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn xcb_presentation_support_unchecked<C>(
&self,
queue_family_index: u32,
connection: *const C,
visual_id: ash::vk::VisualID,
) -> bool {
let fns = self.instance.fns();
(fns.khr_xcb_surface
.get_physical_device_xcb_presentation_support_khr)(
self.handle,
queue_family_index,
connection as *mut _,
visual_id,
) != 0
}
/// Queries whether the physical device supports presenting to Xlib surfaces from queues of the
/// given queue family.
///
/// # Safety
///
/// - `display` must be a valid Xlib `Display` handle.
pub unsafe fn xlib_presentation_support<D>(
&self,
queue_family_index: u32,
display: *const D,
visual_id: ash::vk::VisualID,
) -> Result<bool, PhysicalDeviceError> {
self.validate_xlib_presentation_support(queue_family_index, display, visual_id)?;
Ok(self.xlib_presentation_support_unchecked(queue_family_index, display, visual_id))
}
fn validate_xlib_presentation_support<D>(
&self,
queue_family_index: u32,
_display: *const D,
_visual_id: ash::vk::VisualID,
) -> Result<(), PhysicalDeviceError> {
if !self.instance.enabled_extensions().khr_xlib_surface {
return Err(PhysicalDeviceError::RequirementNotMet {
required_for: "`PhysicalDevice::xlib_presentation_support`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_xlib_surface"],
..Default::default()
},
});
}
// VUID-vkGetPhysicalDeviceXlibPresentationSupportKHR-queueFamilyIndex-01315
if queue_family_index >= self.queue_family_properties.len() as u32 {
return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count: self.queue_family_properties.len() as u32,
});
}
// VUID-vkGetPhysicalDeviceXlibPresentationSupportKHR-dpy-parameter
// Can't validate, therefore unsafe
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn xlib_presentation_support_unchecked<D>(
&self,
queue_family_index: u32,
display: *const D,
visual_id: ash::vk::VisualID,
) -> bool {
let fns = self.instance.fns();
(fns.khr_xlib_surface
.get_physical_device_xlib_presentation_support_khr)(
self.handle,
queue_family_index,
display as *mut _,
visual_id,
) != 0
}
}
unsafe impl VulkanObject for PhysicalDevice {
type Handle = ash::vk::PhysicalDevice;
#[inline]
fn handle(&self) -> Self::Handle {
self.handle
}
}
impl_id_counter!(PhysicalDevice);
vulkan_enum! {
#[non_exhaustive]
/// Type of a physical device.
PhysicalDeviceType = PhysicalDeviceType(i32);
/// The device is an integrated GPU.
IntegratedGpu = INTEGRATED_GPU,
/// The device is a discrete GPU.
DiscreteGpu = DISCRETE_GPU,
/// The device is a virtual GPU.
VirtualGpu = VIRTUAL_GPU,
/// The device is a CPU.
Cpu = CPU,
/// The device is something else.
Other = OTHER,
}
impl Default for PhysicalDeviceType {
#[inline]
fn default() -> Self {
PhysicalDeviceType::Other
}
}
/// The version of the Vulkan conformance test that a driver is conformant against.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ConformanceVersion {
pub major: u8,
pub minor: u8,
pub subminor: u8,
pub patch: u8,
}
impl From<ash::vk::ConformanceVersion> for ConformanceVersion {
#[inline]
fn from(val: ash::vk::ConformanceVersion) -> Self {
ConformanceVersion {
major: val.major,
minor: val.minor,
subminor: val.subminor,
patch: val.patch,
}
}
}
impl Debug for ConformanceVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl Display for ConformanceVersion {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
Debug::fmt(self, f)
}
}
vulkan_enum! {
#[non_exhaustive]
/// An identifier for the driver of a physical device.
DriverId = DriverId(i32);
// TODO: document
AMDProprietary = AMD_PROPRIETARY,
// TODO: document
AMDOpenSource = AMD_OPEN_SOURCE,
// TODO: document
MesaRADV = MESA_RADV,
// TODO: document
NvidiaProprietary = NVIDIA_PROPRIETARY,
// TODO: document
IntelProprietaryWindows = INTEL_PROPRIETARY_WINDOWS,
// TODO: document
IntelOpenSourceMesa = INTEL_OPEN_SOURCE_MESA,
// TODO: document
ImaginationProprietary = IMAGINATION_PROPRIETARY,
// TODO: document
QualcommProprietary = QUALCOMM_PROPRIETARY,
// TODO: document
ARMProprietary = ARM_PROPRIETARY,
// TODO: document
GoogleSwiftshader = GOOGLE_SWIFTSHADER,
// TODO: document
GGPProprietary = GGP_PROPRIETARY,
// TODO: document
BroadcomProprietary = BROADCOM_PROPRIETARY,
// TODO: document
MesaLLVMpipe = MESA_LLVMPIPE,
// TODO: document
MoltenVK = MOLTENVK,
// TODO: document
CoreAVIProprietary = COREAVI_PROPRIETARY,
// TODO: document
JuiceProprietary = JUICE_PROPRIETARY,
// TODO: document
VeriSiliconPropertary = VERISILICON_PROPRIETARY,
// TODO: document
MesaTurnip = MESA_TURNIP,
// TODO: document
MesaV3DV = MESA_V3DV,
// TODO: document
MesaPanVK = MESA_PANVK,
// TODO: document
SamsungProprietary = SAMSUNG_PROPRIETARY,
// TODO: document
MesaVenus = MESA_VENUS,
// TODO: document
MesaDozen = MESA_DOZEN,
}
/// Information provided about an active tool.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ToolProperties {
/// The name of the tool.
pub name: String,
/// The version of the tool.
pub version: String,
/// The purposes supported by the tool.
pub purposes: ToolPurposes,
/// A description of the tool.
pub description: String,
/// The layer implementing the tool, or empty if it is not implemented by a layer.
pub layer: String,
}
vulkan_bitflags! {
#[non_exhaustive]
/// The purpose of an active tool.
ToolPurposes = ToolPurposeFlags(u32);
/// The tool provides validation of API usage.
VALIDATION = VALIDATION,
/// The tool provides profiling of API usage.
PROFILING = PROFILING,
/// The tool is capturing data about the application's API usage.
TRACING = TRACING,
/// The tool provides additional API features or extensions on top of the underlying
/// implementation.
ADDITIONAL_FEATURES = ADDITIONAL_FEATURES,
/// The tool modifies the API features, limits or extensions presented to the application.
MODIFYING_FEATURES = MODIFYING_FEATURES,
/// The tool reports information to the user via a
/// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger).
DEBUG_REPORTING = DEBUG_REPORTING_EXT {
instance_extensions: [ext_debug_utils, ext_debug_report],
},
/// The tool consumes debug markers or object debug annotation, queue labels or command buffer
/// labels.
DEBUG_MARKERS = DEBUG_MARKERS_EXT {
device_extensions: [ext_debug_marker],
instance_extensions: [ext_debug_utils],
},
}
vulkan_bitflags! {
#[non_exhaustive]
/// Specifies which subgroup operations are supported.
SubgroupFeatures = SubgroupFeatureFlags(u32);
// TODO: document
BASIC = BASIC,
// TODO: document
VOTE = VOTE,
// TODO: document
ARITHMETIC = ARITHMETIC,
// TODO: document
BALLOT = BALLOT,
// TODO: document
SHUFFLE = SHUFFLE,
// TODO: document
SHUFFLE_RELATIVE = SHUFFLE_RELATIVE,
// TODO: document
CLUSTERED = CLUSTERED,
// TODO: document
QUAD = QUAD,
// TODO: document
PARTITIONED = PARTITIONED_NV {
device_extensions: [nv_shader_subgroup_partitioned],
},
}
vulkan_enum! {
#[non_exhaustive]
/// Specifies how the device clips single point primitives.
PointClippingBehavior = PointClippingBehavior(i32);
/// Points are clipped if they lie outside any clip plane, both those bounding the view volume
/// and user-defined clip planes.
AllClipPlanes = ALL_CLIP_PLANES,
/// Points are clipped only if they lie outside a user-defined clip plane.
UserClipPlanesOnly = USER_CLIP_PLANES_ONLY,
}
vulkan_enum! {
#[non_exhaustive]
/// Specifies whether, and how, shader float controls can be set independently.
ShaderFloatControlsIndependence = ShaderFloatControlsIndependence(i32);
// TODO: document
Float32Only = TYPE_32_ONLY,
// TODO: document
All = ALL,
// TODO: document
None = NONE,
}
/// Specifies shader core properties.
#[derive(Clone, Copy, Debug)]
pub struct ShaderCoreProperties {}
impl From<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
#[inline]
fn from(_val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self {
Self {}
}
}
vulkan_bitflags! {
#[non_exhaustive]
// TODO: document
MemoryDecompressionMethods = MemoryDecompressionMethodFlagsNV(u64);
// TODO: document
GDEFLATE_1_0 = GDEFLATE_1_0,
}
vulkan_bitflags! {
#[non_exhaustive]
// TODO: document
OpticalFlowGridSizes = OpticalFlowGridSizeFlagsNV(u32);
// TODO: document
SIZE_1X1 = TYPE_1X1,
// TODO: document
SIZE_2X2 = TYPE_2X2,
// TODO: document
SIZE_4X4 = TYPE_4X4,
// TODO: document
SIZE_8X8 = TYPE_8X8,
}
vulkan_enum! {
#[non_exhaustive]
// TODO: document
PipelineRobustnessBufferBehavior = PipelineRobustnessBufferBehaviorEXT(i32);
// TODO: document
DeviceDefault = DEVICE_DEFAULT,
// TODO: document
Disabled = DISABLED,
// TODO: document
RobustBufferAccess = ROBUST_BUFFER_ACCESS,
// TODO: document
RobustBufferAccess2 = ROBUST_BUFFER_ACCESS_2,
}
vulkan_enum! {
#[non_exhaustive]
// TODO: document
PipelineRobustnessImageBehavior = PipelineRobustnessImageBehaviorEXT(i32);
// TODO: document
DeviceDefault = DEVICE_DEFAULT,
// TODO: document
Disabled = DISABLED,
// TODO: document
RobustImageAccess = ROBUST_IMAGE_ACCESS,
// TODO: document
RobustImageAccess2 = ROBUST_IMAGE_ACCESS_2,
}
vulkan_enum! {
#[non_exhaustive]
// TODO: document
RayTracingInvocationReorderMode = RayTracingInvocationReorderModeNV(i32);
// TODO: document
None = NONE,
// TODO: document
Reorder = REORDER,
}
/// Error that can happen when using a physical device.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PhysicalDeviceError {
VulkanError(VulkanError),
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
// The given `SurfaceInfo` values are not supported for the surface by the physical device.
NotSupported,
/// The provided `queue_family_index` was not less than the number of queue families in the
/// physical device.
QueueFamilyIndexOutOfRange {
queue_family_index: u32,
queue_family_count: u32,
},
// The provided `surface` is not supported by any of the physical device's queue families.
SurfaceNotSupported,
}
impl Error for PhysicalDeviceError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::VulkanError(err) => Some(err),
_ => None,
}
}
}
impl Display for PhysicalDeviceError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::VulkanError(_) => write!(f, "a runtime error occurred"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::NotSupported => write!(
f,
"the given `SurfaceInfo` values are not supported for the surface by the physical \
device",
),
Self::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count,
} => write!(
f,
"the provided `queue_family_index` ({}) was not less than the number of queue \
families in the physical device ({})",
queue_family_index, queue_family_count,
),
Self::SurfaceNotSupported => write!(
f,
"the provided `surface` is not supported by any of the physical device's queue families",
),
}
}
}
impl From<VulkanError> for PhysicalDeviceError {
fn from(err: VulkanError) -> Self {
Self::VulkanError(err)
}
}
impl From<RequirementNotMet> for PhysicalDeviceError {
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}