mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Add support for instance and device versions, check version in vulkano-shaders (#1569)
* Move physical device functions into their own module * Add method to FunctionPointers to query Vulkan api version * Store the versions of instances and devices, allow user to query * Check Vulkan version in vulkano-shaders, changelog * Small mistake in changelog
This commit is contained in:
parent
8c0630d3c8
commit
6f3deceb8b
@ -3,7 +3,10 @@
|
||||
Please add new changes at the bottom, preceded by a hyphen -.
|
||||
Breaking changes should be listed first, before other changes, and should be preceded by - **Breaking**.
|
||||
-->
|
||||
|
||||
- **Breaking** Vulkano-shaders now checks if the device supports the shader's SPIR-V version, when loading the shader.
|
||||
- Added `DeviceExtensions::khr_spirv_1_4`, which allows SPIR-V 1.4 shaders in Vulkan versions below 1.2.
|
||||
- Added `FunctionPointers::api_version` to query the highest supported instance version.
|
||||
- Added `Instance::api_version` and `Device::api_version` to return the actual supported Vulkan version. These may differ between instance and device, and be lower than what `FunctionPointers::api_version` and `PhysicalDevice::api_version` return (currently never higher than 1.1, but this may change in the future).
|
||||
|
||||
# Version 0.23.0 (2021-04-10)
|
||||
|
||||
|
@ -215,6 +215,33 @@ where
|
||||
|
||||
// checking whether each required capability is enabled in the Vulkan device
|
||||
let mut cap_checks: Vec<TokenStream> = vec![];
|
||||
match doc.version {
|
||||
(1, 0) => {}
|
||||
(1, 1) | (1, 2) | (1, 3) => {
|
||||
cap_checks.push(quote! {
|
||||
if device.api_version() < (Version { major: 1, minor: 1, patch: 0 }) {
|
||||
panic!("Device API version 1.1 required");
|
||||
}
|
||||
});
|
||||
}
|
||||
(1, 4) => {
|
||||
cap_checks.push(quote! {
|
||||
if device.api_version() < (Version { major: 1, minor: 2, patch: 0 })
|
||||
&& !device.loaded_extensions().khr_spirv_1_4 {
|
||||
panic!("Device API version 1.2 or extension VK_KHR_spirv_1_4 required");
|
||||
}
|
||||
});
|
||||
}
|
||||
(1, 5) => {
|
||||
cap_checks.push(quote! {
|
||||
if device.api_version() < (Version { major: 1, minor: 2, patch: 0 }) {
|
||||
panic!("Device API version 1.2 required");
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => return Err(Error::UnsupportedSpirvVersion),
|
||||
}
|
||||
|
||||
for i in doc.instructions.iter() {
|
||||
let dev_req = {
|
||||
match i {
|
||||
@ -325,6 +352,8 @@ where
|
||||
use vulkano::pipeline::shader::SpecializationConstants as SpecConstsTrait;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::pipeline::shader::SpecializationMapEntry;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::Version;
|
||||
|
||||
pub struct #struct_name {
|
||||
shader: ::std::sync::Arc<::vulkano::pipeline::shader::ShaderModule>,
|
||||
@ -379,6 +408,7 @@ where
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
UnsupportedSpirvVersion,
|
||||
IoError(IoError),
|
||||
ParseError(ParseError),
|
||||
}
|
||||
|
@ -128,23 +128,26 @@ device_extensions! {
|
||||
// https://vulkan.lunarg.com/doc/view/1.2.162.1/mac/1.2-extensions/vkspec.html#VUID-VkDeviceCreateInfo-pProperties-04451
|
||||
khr_portability_subset,
|
||||
],
|
||||
khr_swapchain => b"VK_KHR_swapchain",
|
||||
khr_display_swapchain => b"VK_KHR_display_swapchain",
|
||||
khr_sampler_mirror_clamp_to_edge => b"VK_KHR_sampler_mirror_clamp_to_edge",
|
||||
khr_maintenance1 => b"VK_KHR_maintenance1",
|
||||
khr_get_memory_requirements2 => b"VK_KHR_get_memory_requirements2",
|
||||
khr_dedicated_allocation => b"VK_KHR_dedicated_allocation",
|
||||
khr_incremental_present => b"VK_KHR_incremental_present",
|
||||
|
||||
// List in order: khr, ext, then alphabetical
|
||||
khr_16bit_storage => b"VK_KHR_16bit_storage",
|
||||
khr_8bit_storage => b"VK_KHR_8bit_storage",
|
||||
khr_storage_buffer_storage_class => b"VK_KHR_storage_buffer_storage_class",
|
||||
ext_debug_utils => b"VK_EXT_debug_utils",
|
||||
khr_multiview => b"VK_KHR_multiview",
|
||||
ext_full_screen_exclusive => b"VK_EXT_full_screen_exclusive",
|
||||
khr_dedicated_allocation => b"VK_KHR_dedicated_allocation",
|
||||
khr_display_swapchain => b"VK_KHR_display_swapchain",
|
||||
khr_external_memory => b"VK_KHR_external_memory",
|
||||
khr_external_memory_fd => b"VK_KHR_external_memory_fd",
|
||||
ext_external_memory_dmabuf => b"VK_EXT_external_memory_dma_buf",
|
||||
khr_get_memory_requirements2 => b"VK_KHR_get_memory_requirements2",
|
||||
khr_incremental_present => b"VK_KHR_incremental_present",
|
||||
khr_maintenance1 => b"VK_KHR_maintenance1",
|
||||
khr_multiview => b"VK_KHR_multiview",
|
||||
khr_portability_subset => b"VK_KHR_portability_subset",
|
||||
khr_sampler_mirror_clamp_to_edge => b"VK_KHR_sampler_mirror_clamp_to_edge",
|
||||
khr_spirv_1_4 => b"VK_KHR_spirv_1_4",
|
||||
khr_storage_buffer_storage_class => b"VK_KHR_storage_buffer_storage_class",
|
||||
khr_swapchain => b"VK_KHR_swapchain",
|
||||
ext_debug_utils => b"VK_EXT_debug_utils",
|
||||
ext_external_memory_dmabuf => b"VK_EXT_external_memory_dma_buf",
|
||||
ext_full_screen_exclusive => b"VK_EXT_full_screen_exclusive",
|
||||
}
|
||||
|
||||
/// This helper type can only be instantiated inside this module.
|
||||
|
@ -130,6 +130,7 @@ use crate::image::ImageFormatProperties;
|
||||
use crate::image::ImageTiling;
|
||||
use crate::image::ImageType;
|
||||
use crate::image::ImageUsage;
|
||||
use crate::Version;
|
||||
use std::pin::Pin;
|
||||
|
||||
/// Represents a Vulkan context.
|
||||
@ -137,6 +138,11 @@ pub struct Device {
|
||||
instance: Arc<Instance>,
|
||||
physical_device: usize,
|
||||
device: vk::Device,
|
||||
|
||||
// The highest version that is supported for this device.
|
||||
// This is the minimum of Instance::desired_version and PhysicalDevice::api_version.
|
||||
api_version: Version,
|
||||
|
||||
vk: vk::DevicePointers,
|
||||
standard_pool: Mutex<Weak<StdMemoryPool>>,
|
||||
standard_descriptor_pool: Mutex<Weak<StdDescriptorPool>>,
|
||||
@ -187,6 +193,9 @@ impl Device {
|
||||
I: IntoIterator<Item = (QueueFamily<'a>, f32)>,
|
||||
Ext: Into<RawDeviceExtensions>,
|
||||
{
|
||||
let desired_version = phys.instance().desired_version;
|
||||
let api_version = std::cmp::min(desired_version, phys.api_version());
|
||||
|
||||
let queue_families = queue_families.into_iter();
|
||||
|
||||
if !phys.supported_features().superset_of(&requested_features) {
|
||||
@ -329,6 +338,7 @@ impl Device {
|
||||
instance: phys.instance().clone(),
|
||||
physical_device: phys.index(),
|
||||
device: device,
|
||||
api_version,
|
||||
vk: vk,
|
||||
standard_pool: Mutex::new(Weak::new()),
|
||||
standard_descriptor_pool: Mutex::new(Weak::new()),
|
||||
@ -356,6 +366,12 @@ impl Device {
|
||||
Ok((device, output_queues))
|
||||
}
|
||||
|
||||
/// Returns the Vulkan version supported by this `Device`.
|
||||
#[inline]
|
||||
pub fn api_version(&self) -> Version {
|
||||
self.api_version
|
||||
}
|
||||
|
||||
/// Grants access to the pointers to the Vulkan functions of the device.
|
||||
#[inline]
|
||||
pub fn pointers(&self) -> &vk::DevicePointers {
|
||||
|
@ -145,30 +145,32 @@ macro_rules! instance_extensions {
|
||||
instance_extensions! {
|
||||
InstanceExtensions,
|
||||
RawInstanceExtensions,
|
||||
khr_surface => b"VK_KHR_surface",
|
||||
khr_display => b"VK_KHR_display",
|
||||
khr_xlib_surface => b"VK_KHR_xlib_surface",
|
||||
khr_xcb_surface => b"VK_KHR_xcb_surface",
|
||||
khr_wayland_surface => b"VK_KHR_wayland_surface",
|
||||
|
||||
// List in order: khr, ext, then alphabetical
|
||||
khr_android_surface => b"VK_KHR_android_surface",
|
||||
khr_win32_surface => b"VK_KHR_win32_surface",
|
||||
ext_debug_utils => b"VK_EXT_debug_utils",
|
||||
mvk_ios_surface => b"VK_MVK_ios_surface",
|
||||
mvk_macos_surface => b"VK_MVK_macos_surface",
|
||||
mvk_moltenvk => b"VK_MVK_moltenvk", // TODO: confirm that it's an instance extension
|
||||
nn_vi_surface => b"VK_NN_vi_surface",
|
||||
ext_swapchain_colorspace => b"VK_EXT_swapchain_colorspace",
|
||||
khr_get_physical_device_properties2 => b"VK_KHR_get_physical_device_properties2",
|
||||
khr_get_surface_capabilities2 => b"VK_KHR_get_surface_capabilities2",
|
||||
khr_device_group_creation => b"VK_KHR_device_group_creation",
|
||||
khr_display => b"VK_KHR_display",
|
||||
khr_external_fence_capabilities => b"VK_KHR_external_fence_capabilities",
|
||||
khr_external_memory_capabilities => b"VK_KHR_external_memory_capabilities",
|
||||
khr_external_semaphore_capabilities => b"VK_KHR_external_semaphore_capabilities",
|
||||
khr_get_display_properties2 => b"VK_KHR_get_display_properties2",
|
||||
khr_get_physical_device_properties2 => b"VK_KHR_get_physical_device_properties2",
|
||||
khr_get_surface_capabilities2 => b"VK_KHR_get_surface_capabilities2",
|
||||
khr_surface => b"VK_KHR_surface",
|
||||
khr_wayland_surface => b"VK_KHR_wayland_surface",
|
||||
khr_win32_surface => b"VK_KHR_win32_surface",
|
||||
khr_xcb_surface => b"VK_KHR_xcb_surface",
|
||||
khr_xlib_surface => b"VK_KHR_xlib_surface",
|
||||
ext_acquire_xlib_display => b"VK_EXT_acquire_xlib_display",
|
||||
ext_debug_report => b"VK_EXT_debug_report",
|
||||
ext_debug_utils => b"VK_EXT_debug_utils",
|
||||
ext_direct_mode_display => b"VK_EXT_direct_mode_display",
|
||||
ext_display_surface_counter => b"VK_EXT_display_surface_counter",
|
||||
ext_swapchain_colorspace => b"VK_EXT_swapchain_colorspace",
|
||||
mvk_ios_surface => b"VK_MVK_ios_surface",
|
||||
mvk_macos_surface => b"VK_MVK_macos_surface",
|
||||
mvk_moltenvk => b"VK_MVK_moltenvk", // TODO: confirm that it's an instance extension
|
||||
nn_vi_surface => b"VK_NN_vi_surface",
|
||||
}
|
||||
|
||||
/// This helper type can only be instantiated inside this module.
|
||||
|
@ -8,28 +8,24 @@
|
||||
// according to those terms.
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::features::{Features, FeaturesFfi};
|
||||
use crate::instance::limits::Limits;
|
||||
use crate::instance::loader;
|
||||
use crate::instance::loader::FunctionPointers;
|
||||
use crate::instance::loader::Loader;
|
||||
use crate::instance::loader::LoadingError;
|
||||
use crate::instance::physical_device::{init_physical_devices, PhysicalDeviceInfos};
|
||||
use crate::instance::{InstanceExtensions, RawInstanceExtensions};
|
||||
use crate::sync::PipelineStage;
|
||||
use crate::version::Version;
|
||||
use crate::vk;
|
||||
use crate::Error;
|
||||
use crate::OomError;
|
||||
use crate::Version;
|
||||
use crate::VulkanObject;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
use std::error;
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::CString;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
use std::mem;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
@ -94,7 +90,16 @@ use std::sync::Arc;
|
||||
pub struct Instance {
|
||||
instance: vk::Instance,
|
||||
//alloc: Option<Box<Alloc + Send + Sync>>,
|
||||
physical_devices: Vec<PhysicalDeviceInfos>,
|
||||
|
||||
// The desired API version for instances and devices created from it.
|
||||
// TODO: allow the user to specify this on construction.
|
||||
pub(crate) desired_version: Version,
|
||||
|
||||
// The highest version that is supported for this instance.
|
||||
// This is the minimum of Instance::desired_version and FunctionPointers::api_version.
|
||||
api_version: Version,
|
||||
|
||||
pub(super) physical_devices: Vec<PhysicalDeviceInfos>,
|
||||
vk: vk::InstancePointers,
|
||||
extensions: RawInstanceExtensions,
|
||||
layers: SmallVec<[CString; 16]>,
|
||||
@ -208,6 +213,21 @@ impl Instance {
|
||||
None
|
||||
};
|
||||
|
||||
// TODO: allow the user to specify this.
|
||||
// Vulkan 1.0 will return VK_ERROR_INCOMPATIBLE_DRIVER on instance creation if this isn't
|
||||
// 1.0, but higher versions never return this error, and thus will allow a desired version
|
||||
// beyond what they support. The actual support on that particular instance/device is the
|
||||
// minimum of desired and supported.
|
||||
// In other words, it's impossible to use a Vulkan 1.1 or 1.2 device with a 1.0 instance,
|
||||
// because instance creation with a higher desired_version will fail. But it is possible to
|
||||
// use a 1.0 or 1.2 device with a 1.1 instance.
|
||||
let desired_version = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
};
|
||||
let api_version = std::cmp::min(desired_version, function_pointers.api_version()?);
|
||||
|
||||
// Building the `vk::ApplicationInfo` if required.
|
||||
let app_infos = if let Some(app_infos) = app_infos {
|
||||
Some(vk::ApplicationInfo {
|
||||
@ -235,12 +255,7 @@ impl Instance {
|
||||
.engine_version
|
||||
.map(|v| v.into_vulkan_version())
|
||||
.unwrap_or(0),
|
||||
apiVersion: Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
}
|
||||
.into_vulkan_version(), // TODO:
|
||||
apiVersion: desired_version.into_vulkan_version(), // TODO:
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -282,38 +297,18 @@ impl Instance {
|
||||
|
||||
// Loading the function pointers of the newly-created instance.
|
||||
let vk = {
|
||||
vk::InstancePointers::load(|name| unsafe {
|
||||
mem::transmute(function_pointers.get_instance_proc_addr(instance, name.as_ptr()))
|
||||
vk::InstancePointers::load(|name| {
|
||||
function_pointers.get_instance_proc_addr(instance, name.as_ptr())
|
||||
})
|
||||
};
|
||||
|
||||
// Enumerating all physical devices.
|
||||
let physical_devices: Vec<vk::PhysicalDevice> = unsafe {
|
||||
let mut num = 0;
|
||||
check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, ptr::null_mut()))?;
|
||||
|
||||
let mut devices = Vec::with_capacity(num as usize);
|
||||
check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, devices.as_mut_ptr()))?;
|
||||
devices.set_len(num as usize);
|
||||
devices
|
||||
};
|
||||
|
||||
let vk_khr_get_physical_device_properties2 =
|
||||
CString::new(b"VK_KHR_get_physical_device_properties2".to_vec()).unwrap();
|
||||
|
||||
// Getting the properties of all physical devices.
|
||||
// If possible, we use VK_KHR_get_physical_device_properties2.
|
||||
let physical_devices = if extensions
|
||||
.iter()
|
||||
.any(|v| *v == vk_khr_get_physical_device_properties2)
|
||||
{
|
||||
Instance::init_physical_devices2(&vk, physical_devices, &extensions)
|
||||
} else {
|
||||
Instance::init_physical_devices(&vk, physical_devices)
|
||||
};
|
||||
let physical_devices = init_physical_devices(instance, &vk, &extensions)?;
|
||||
|
||||
Ok(Arc::new(Instance {
|
||||
instance,
|
||||
api_version,
|
||||
desired_version,
|
||||
//alloc: None,
|
||||
physical_devices,
|
||||
vk,
|
||||
@ -323,145 +318,6 @@ impl Instance {
|
||||
}))
|
||||
}
|
||||
|
||||
/// Initialize all physical devices
|
||||
fn init_physical_devices(
|
||||
vk: &vk::InstancePointers,
|
||||
physical_devices: Vec<vk::PhysicalDevice>,
|
||||
) -> Vec<PhysicalDeviceInfos> {
|
||||
let mut output = Vec::with_capacity(physical_devices.len());
|
||||
|
||||
for device in physical_devices.into_iter() {
|
||||
let properties: vk::PhysicalDeviceProperties = unsafe {
|
||||
let mut output = MaybeUninit::uninit();
|
||||
vk.GetPhysicalDeviceProperties(device, output.as_mut_ptr());
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
let queue_families = unsafe {
|
||||
let mut num = 0;
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, ptr::null_mut());
|
||||
|
||||
let mut families = Vec::with_capacity(num as usize);
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, families.as_mut_ptr());
|
||||
families.set_len(num as usize);
|
||||
families
|
||||
};
|
||||
|
||||
let memory: vk::PhysicalDeviceMemoryProperties = unsafe {
|
||||
let mut output = MaybeUninit::uninit();
|
||||
vk.GetPhysicalDeviceMemoryProperties(device, output.as_mut_ptr());
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
let available_features: vk::PhysicalDeviceFeatures = unsafe {
|
||||
let mut output = MaybeUninit::uninit();
|
||||
vk.GetPhysicalDeviceFeatures(device, output.as_mut_ptr());
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
output.push(PhysicalDeviceInfos {
|
||||
device,
|
||||
properties,
|
||||
extended_properties: PhysicalDeviceExtendedProperties::empty(),
|
||||
memory,
|
||||
queue_families,
|
||||
available_features: Features::from(available_features),
|
||||
});
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
/// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2
|
||||
/// TODO: Query extension-specific physical device properties, once a new instance extension is supported.
|
||||
fn init_physical_devices2(
|
||||
vk: &vk::InstancePointers,
|
||||
physical_devices: Vec<vk::PhysicalDevice>,
|
||||
extensions: &RawInstanceExtensions,
|
||||
) -> Vec<PhysicalDeviceInfos> {
|
||||
let mut output = Vec::with_capacity(physical_devices.len());
|
||||
|
||||
for device in physical_devices.into_iter() {
|
||||
let mut extended_properties = PhysicalDeviceExtendedProperties::empty();
|
||||
|
||||
let properties: vk::PhysicalDeviceProperties = unsafe {
|
||||
let mut subgroup_properties = vk::PhysicalDeviceSubgroupProperties {
|
||||
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES,
|
||||
pNext: ptr::null_mut(),
|
||||
subgroupSize: 0,
|
||||
supportedStages: 0,
|
||||
supportedOperations: 0,
|
||||
quadOperationsInAllStages: 0,
|
||||
};
|
||||
|
||||
let mut output = vk::PhysicalDeviceProperties2KHR {
|
||||
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
|
||||
pNext: &mut subgroup_properties,
|
||||
properties: mem::zeroed(),
|
||||
};
|
||||
|
||||
vk.GetPhysicalDeviceProperties2KHR(device, &mut output);
|
||||
|
||||
extended_properties = PhysicalDeviceExtendedProperties {
|
||||
subgroup_size: Some(subgroup_properties.subgroupSize),
|
||||
|
||||
..extended_properties
|
||||
};
|
||||
|
||||
output.properties
|
||||
};
|
||||
|
||||
let queue_families = unsafe {
|
||||
let mut num = 0;
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties2KHR(device, &mut num, ptr::null_mut());
|
||||
|
||||
let mut families = (0..num)
|
||||
.map(|_| vk::QueueFamilyProperties2KHR {
|
||||
sType: vk::STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR,
|
||||
pNext: ptr::null_mut(),
|
||||
queueFamilyProperties: mem::zeroed(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties2KHR(
|
||||
device,
|
||||
&mut num,
|
||||
families.as_mut_ptr(),
|
||||
);
|
||||
families
|
||||
.into_iter()
|
||||
.map(|family| family.queueFamilyProperties)
|
||||
.collect()
|
||||
};
|
||||
|
||||
let memory: vk::PhysicalDeviceMemoryProperties = unsafe {
|
||||
let mut output = vk::PhysicalDeviceMemoryProperties2KHR {
|
||||
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR,
|
||||
pNext: ptr::null_mut(),
|
||||
memoryProperties: mem::zeroed(),
|
||||
};
|
||||
vk.GetPhysicalDeviceMemoryProperties2KHR(device, &mut output);
|
||||
output.memoryProperties
|
||||
};
|
||||
|
||||
let available_features: Features = unsafe {
|
||||
let mut output = FeaturesFfi::new();
|
||||
let ptr = FeaturesFfi::mut_base_ptr(&mut output) as *mut _;
|
||||
vk.GetPhysicalDeviceFeatures2KHR(device, ptr);
|
||||
Features::from(&output.main)
|
||||
};
|
||||
|
||||
output.push(PhysicalDeviceInfos {
|
||||
device,
|
||||
properties,
|
||||
extended_properties,
|
||||
memory,
|
||||
queue_families,
|
||||
available_features,
|
||||
});
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
/*/// Same as `new`, but provides an allocator that will be used by the Vulkan library whenever
|
||||
/// it needs to allocate memory on the host.
|
||||
///
|
||||
@ -470,6 +326,12 @@ impl Instance {
|
||||
unimplemented!()
|
||||
}*/
|
||||
|
||||
/// Returns the Vulkan version supported by this `Instance`.
|
||||
#[inline]
|
||||
pub fn api_version(&self) -> Version {
|
||||
self.api_version
|
||||
}
|
||||
|
||||
/// Grants access to the Vulkan functions of the instance.
|
||||
#[inline]
|
||||
pub fn pointers(&self) -> &vk::InstancePointers {
|
||||
@ -724,706 +586,6 @@ impl From<Error> for InstanceCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
struct PhysicalDeviceInfos {
|
||||
device: vk::PhysicalDevice,
|
||||
properties: vk::PhysicalDeviceProperties,
|
||||
extended_properties: PhysicalDeviceExtendedProperties,
|
||||
queue_families: Vec<vk::QueueFamilyProperties>,
|
||||
memory: vk::PhysicalDeviceMemoryProperties,
|
||||
available_features: Features,
|
||||
}
|
||||
|
||||
/// Represents additional information related to Physical Devices fetched from
|
||||
/// `vkGetPhysicalDeviceProperties` call. Certain features available only when
|
||||
/// appropriate `Instance` extensions enabled. The core extension required
|
||||
/// for this features is `InstanceExtensions::khr_get_physical_device_properties2`
|
||||
///
|
||||
/// TODO: Only a small subset of available properties(https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties2.html) is implemented at this moment.
|
||||
pub struct PhysicalDeviceExtendedProperties {
|
||||
subgroup_size: Option<u32>,
|
||||
}
|
||||
|
||||
impl PhysicalDeviceExtendedProperties {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
subgroup_size: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The default number of invocations in each subgroup
|
||||
///
|
||||
/// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html for details
|
||||
#[inline]
|
||||
pub fn subgroup_size(&self) -> &Option<u32> {
|
||||
&self.subgroup_size
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents one of the available devices on this machine.
|
||||
///
|
||||
/// This struct simply contains a pointer to an instance and a number representing the physical
|
||||
/// device. You are therefore encouraged to pass this around by value instead of by reference.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use vulkano::instance::Instance;
|
||||
/// # use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// for physical_device in PhysicalDevice::enumerate(&instance) {
|
||||
/// print_infos(physical_device);
|
||||
/// }
|
||||
///
|
||||
/// fn print_infos(dev: PhysicalDevice) {
|
||||
/// println!("Name: {}", dev.name());
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PhysicalDevice<'a> {
|
||||
instance: &'a Arc<Instance>,
|
||||
device: usize,
|
||||
}
|
||||
|
||||
impl<'a> PhysicalDevice<'a> {
|
||||
/// Returns an iterator that enumerates the physical devices available.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use vulkano::instance::Instance;
|
||||
/// # use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// for physical_device in PhysicalDevice::enumerate(&instance) {
|
||||
/// println!("Available device: {}", physical_device.name());
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn enumerate(instance: &'a Arc<Instance>) -> PhysicalDevicesIter<'a> {
|
||||
PhysicalDevicesIter {
|
||||
instance,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a physical device from its index. Returns `None` if out of range.
|
||||
///
|
||||
/// Indices range from 0 to the number of devices.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use vulkano::instance::Instance;
|
||||
/// use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_index(instance: &'a Arc<Instance>, index: usize) -> Option<PhysicalDevice<'a>> {
|
||||
if instance.physical_devices.len() > index {
|
||||
Some(PhysicalDevice {
|
||||
instance,
|
||||
device: index,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the instance corresponding to this physical device.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// fn do_something(physical_device: PhysicalDevice) {
|
||||
/// let _loaded_extensions = physical_device.instance().loaded_extensions();
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn instance(&self) -> &'a Arc<Instance> {
|
||||
&self.instance
|
||||
}
|
||||
|
||||
/// Returns the index of the physical device in the physical devices list.
|
||||
///
|
||||
/// This index never changes and can be used later to retrieve a `PhysicalDevice` from an
|
||||
/// instance and an index.
|
||||
#[inline]
|
||||
pub fn index(&self) -> usize {
|
||||
self.device
|
||||
}
|
||||
|
||||
/// Returns the human-readable name of the device.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
unsafe {
|
||||
let val = &self.infos().properties.deviceName;
|
||||
let val = CStr::from_ptr(val.as_ptr());
|
||||
val.to_str()
|
||||
.expect("physical device name contained non-UTF8 characters")
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the type of the device.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use vulkano::instance::Instance;
|
||||
/// # use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// for physical_device in PhysicalDevice::enumerate(&instance) {
|
||||
/// println!("Available device: {} (type: {:?})",
|
||||
/// physical_device.name(), physical_device.ty());
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ty(&self) -> PhysicalDeviceType {
|
||||
match self.instance.physical_devices[self.device]
|
||||
.properties
|
||||
.deviceType
|
||||
{
|
||||
vk::PHYSICAL_DEVICE_TYPE_OTHER => PhysicalDeviceType::Other,
|
||||
vk::PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => PhysicalDeviceType::IntegratedGpu,
|
||||
vk::PHYSICAL_DEVICE_TYPE_DISCRETE_GPU => PhysicalDeviceType::DiscreteGpu,
|
||||
vk::PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU => PhysicalDeviceType::VirtualGpu,
|
||||
vk::PHYSICAL_DEVICE_TYPE_CPU => PhysicalDeviceType::Cpu,
|
||||
_ => panic!("Unrecognized Vulkan device type"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the version of Vulkan supported by this device.
|
||||
#[inline]
|
||||
pub fn api_version(&self) -> Version {
|
||||
let val = self.infos().properties.apiVersion;
|
||||
Version::from_vulkan_version(val)
|
||||
}
|
||||
|
||||
/// Returns the Vulkan features that are supported by this physical device.
|
||||
#[inline]
|
||||
pub fn supported_features(&self) -> &'a Features {
|
||||
&self.infos().available_features
|
||||
}
|
||||
|
||||
/// Builds an iterator that enumerates all the queue families on this physical device.
|
||||
#[inline]
|
||||
pub fn queue_families(&self) -> QueueFamiliesIter<'a> {
|
||||
QueueFamiliesIter {
|
||||
physical_device: *self,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the queue family with the given index, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn queue_family_by_id(&self, id: u32) -> Option<QueueFamily<'a>> {
|
||||
if (id as usize) < self.infos().queue_families.len() {
|
||||
Some(QueueFamily {
|
||||
physical_device: *self,
|
||||
id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an iterator that enumerates all the memory types on this physical device.
|
||||
#[inline]
|
||||
pub fn memory_types(&self) -> MemoryTypesIter<'a> {
|
||||
MemoryTypesIter {
|
||||
physical_device: *self,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the memory type with the given index, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn memory_type_by_id(&self, id: u32) -> Option<MemoryType<'a>> {
|
||||
if id < self.infos().memory.memoryTypeCount {
|
||||
Some(MemoryType {
|
||||
physical_device: *self,
|
||||
id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an iterator that enumerates all the memory heaps on this physical device.
|
||||
#[inline]
|
||||
pub fn memory_heaps(&self) -> MemoryHeapsIter<'a> {
|
||||
MemoryHeapsIter {
|
||||
physical_device: *self,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the memory heap with the given index, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn memory_heap_by_id(&self, id: u32) -> Option<MemoryHeap<'a>> {
|
||||
if id < self.infos().memory.memoryHeapCount {
|
||||
Some(MemoryHeap {
|
||||
physical_device: *self,
|
||||
id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Gives access to the limits of the physical device.
|
||||
///
|
||||
/// This function should be zero-cost in release mode. It only exists to not pollute the
|
||||
/// namespace of `PhysicalDevice` with all the limits-related getters.
|
||||
#[inline]
|
||||
pub fn limits(&self) -> Limits<'a> {
|
||||
Limits::from_vk_limits(&self.infos().properties.limits)
|
||||
}
|
||||
|
||||
/// Returns an opaque number representing the version of the driver of this device.
|
||||
///
|
||||
/// The meaning of this number is implementation-specific. It can be used in bug reports, for
|
||||
/// example.
|
||||
#[inline]
|
||||
pub fn driver_version(&self) -> u32 {
|
||||
self.infos().properties.driverVersion
|
||||
}
|
||||
|
||||
/// Returns the PCI ID of the device.
|
||||
#[inline]
|
||||
pub fn pci_device_id(&self) -> u32 {
|
||||
self.infos().properties.deviceID
|
||||
}
|
||||
|
||||
/// Returns the PCI ID of the vendor.
|
||||
#[inline]
|
||||
pub fn pci_vendor_id(&self) -> u32 {
|
||||
self.infos().properties.vendorID
|
||||
}
|
||||
|
||||
/// Returns a unique identifier for the device.
|
||||
///
|
||||
/// Can be stored in a configuration file, so that you can retrieve the device again the next
|
||||
/// time the program is run.
|
||||
#[inline]
|
||||
pub fn uuid(&self) -> &[u8; 16] {
|
||||
// must be equal to vk::UUID_SIZE
|
||||
&self.infos().properties.pipelineCacheUUID
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extended_properties(&self) -> &PhysicalDeviceExtendedProperties {
|
||||
&self.infos().extended_properties
|
||||
}
|
||||
|
||||
// Internal function to make it easier to get the infos of this device.
|
||||
#[inline]
|
||||
fn infos(&self) -> &'a PhysicalDeviceInfos {
|
||||
&self.instance.physical_devices[self.device]
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> VulkanObject for PhysicalDevice<'a> {
|
||||
type Object = vk::PhysicalDevice;
|
||||
|
||||
const TYPE: vk::ObjectType = vk::OBJECT_TYPE_PHYSICAL_DEVICE;
|
||||
|
||||
#[inline]
|
||||
fn internal_object(&self) -> vk::PhysicalDevice {
|
||||
self.infos().device
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for all the physical devices available on hardware.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PhysicalDevicesIter<'a> {
|
||||
instance: &'a Arc<Instance>,
|
||||
current_id: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PhysicalDevicesIter<'a> {
|
||||
type Item = PhysicalDevice<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<PhysicalDevice<'a>> {
|
||||
if self.current_id >= self.instance.physical_devices.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = PhysicalDevice {
|
||||
instance: self.instance,
|
||||
device: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.instance.physical_devices.len() - self.current_id;
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for PhysicalDevicesIter<'a> {}
|
||||
|
||||
/// Type of a physical device.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
#[repr(u32)]
|
||||
pub enum PhysicalDeviceType {
|
||||
/// The device is an integrated GPU.
|
||||
IntegratedGpu = 1,
|
||||
/// The device is a discrete GPU.
|
||||
DiscreteGpu = 2,
|
||||
/// The device is a virtual GPU.
|
||||
VirtualGpu = 3,
|
||||
/// The device is a CPU.
|
||||
Cpu = 4,
|
||||
/// The device is something else.
|
||||
Other = 0,
|
||||
}
|
||||
|
||||
/// Represents a queue family in a physical device.
|
||||
///
|
||||
/// A queue family is group of one or multiple queues. All queues of one family have the same
|
||||
/// characteristics.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct QueueFamily<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl<'a> QueueFamily<'a> {
|
||||
/// Returns the physical device associated to this queue family.
|
||||
#[inline]
|
||||
pub fn physical_device(&self) -> PhysicalDevice<'a> {
|
||||
self.physical_device
|
||||
}
|
||||
|
||||
/// Returns the identifier of this queue family within the physical device.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns the number of queues that belong to this family.
|
||||
///
|
||||
/// Guaranteed to be at least 1 (or else that family wouldn't exist).
|
||||
#[inline]
|
||||
pub fn queues_count(&self) -> usize {
|
||||
self.physical_device.infos().queue_families[self.id as usize].queueCount as usize
|
||||
}
|
||||
|
||||
/// If timestamps are supported, returns the number of bits supported by timestamp operations.
|
||||
/// The returned value will be in the range 36..64.
|
||||
/// If timestamps are not supported, returns None.
|
||||
#[inline]
|
||||
pub fn timestamp_valid_bits(&self) -> Option<u32> {
|
||||
let value =
|
||||
self.physical_device.infos().queue_families[self.id as usize].timestampValidBits;
|
||||
if value == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the minimum granularity supported for image transfers in terms
|
||||
/// of `[width, height, depth]`
|
||||
#[inline]
|
||||
pub fn min_image_transfer_granularity(&self) -> [u32; 3] {
|
||||
let ref granularity = self.physical_device.infos().queue_families[self.id as usize]
|
||||
.minImageTransferGranularity;
|
||||
[granularity.width, granularity.height, granularity.depth]
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute graphics operations.
|
||||
#[inline]
|
||||
pub fn supports_graphics(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_GRAPHICS_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute compute operations.
|
||||
#[inline]
|
||||
pub fn supports_compute(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_COMPUTE_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute transfer operations.
|
||||
/// > **Note**: While all queues that can perform graphics or compute operations can implicitly perform
|
||||
/// > transfer operations, graphics & compute queues only optionally indicate support for tranfers.
|
||||
/// > Many discrete cards will have one queue family that exclusively sets the VK_QUEUE_TRANSFER_BIT
|
||||
/// > to indicate a special relationship with the DMA module and more efficient transfers.
|
||||
#[inline]
|
||||
pub fn explicitly_supports_transfers(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_TRANSFER_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute sparse resources binding operations.
|
||||
#[inline]
|
||||
pub fn supports_sparse_binding(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_SPARSE_BINDING_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if the queues of this family support a particular pipeline stage.
|
||||
#[inline]
|
||||
pub fn supports_stage(&self, stage: PipelineStage) -> bool {
|
||||
(self.flags() & stage.required_queue_flags()) != 0
|
||||
}
|
||||
|
||||
/// Internal utility function that returns the flags of this queue family.
|
||||
#[inline]
|
||||
fn flags(&self) -> u32 {
|
||||
self.physical_device.infos().queue_families[self.id as usize].queueFlags
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for QueueFamily<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
&& self.physical_device.internal_object() == other.physical_device.internal_object()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Eq for QueueFamily<'a> {}
|
||||
|
||||
/// Iterator for all the queue families available on a physical device.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct QueueFamiliesIter<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
current_id: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for QueueFamiliesIter<'a> {
|
||||
type Item = QueueFamily<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<QueueFamily<'a>> {
|
||||
if self.current_id as usize >= self.physical_device.infos().queue_families.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = QueueFamily {
|
||||
physical_device: self.physical_device,
|
||||
id: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.physical_device.infos().queue_families.len();
|
||||
let remain = len - self.current_id as usize;
|
||||
(remain, Some(remain))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for QueueFamiliesIter<'a> {}
|
||||
|
||||
/// Represents a memory type in a physical device.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MemoryType<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl<'a> MemoryType<'a> {
|
||||
/// Returns the physical device associated to this memory type.
|
||||
#[inline]
|
||||
pub fn physical_device(&self) -> PhysicalDevice<'a> {
|
||||
self.physical_device
|
||||
}
|
||||
|
||||
/// Returns the identifier of this memory type within the physical device.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns the heap that corresponds to this memory type.
|
||||
#[inline]
|
||||
pub fn heap(&self) -> MemoryHeap<'a> {
|
||||
let heap_id = self.physical_device.infos().memory.memoryTypes[self.id as usize].heapIndex;
|
||||
MemoryHeap {
|
||||
physical_device: self.physical_device,
|
||||
id: heap_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the memory type is located on the device, which means that it's the most
|
||||
/// efficient for GPU accesses.
|
||||
#[inline]
|
||||
pub fn is_device_local(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if the memory type can be accessed by the host.
|
||||
#[inline]
|
||||
pub fn is_host_visible(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if modifications made by the host or the GPU on this memory type are
|
||||
/// instantaneously visible to the other party. False means that changes have to be flushed.
|
||||
///
|
||||
/// You don't need to worry about this, as this library handles that for you.
|
||||
#[inline]
|
||||
pub fn is_host_coherent(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if memory of this memory type is cached by the host. Host memory accesses to
|
||||
/// cached memory is faster than for uncached memory. However you are not guaranteed that it
|
||||
/// is coherent.
|
||||
#[inline]
|
||||
pub fn is_host_cached(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_HOST_CACHED_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if allocations made to this memory type is lazy.
|
||||
///
|
||||
/// This means that no actual allocation is performed. Instead memory is automatically
|
||||
/// allocated by the Vulkan implementation.
|
||||
///
|
||||
/// Memory of this type can only be used on images created with a certain flag. Memory of this
|
||||
/// type is never host-visible.
|
||||
#[inline]
|
||||
pub fn is_lazily_allocated(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0
|
||||
}
|
||||
|
||||
/// Internal utility function that returns the flags of this queue family.
|
||||
#[inline]
|
||||
fn flags(&self) -> u32 {
|
||||
self.physical_device.infos().memory.memoryTypes[self.id as usize].propertyFlags
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for all the memory types available on a physical device.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryTypesIter<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
current_id: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for MemoryTypesIter<'a> {
|
||||
type Item = MemoryType<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<MemoryType<'a>> {
|
||||
if self.current_id >= self.physical_device.infos().memory.memoryTypeCount {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = MemoryType {
|
||||
physical_device: self.physical_device,
|
||||
id: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.physical_device.infos().memory.memoryTypeCount;
|
||||
let remain = (len - self.current_id) as usize;
|
||||
(remain, Some(remain))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for MemoryTypesIter<'a> {}
|
||||
|
||||
/// Represents a memory heap in a physical device.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MemoryHeap<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl<'a> MemoryHeap<'a> {
|
||||
/// Returns the physical device associated to this memory heap.
|
||||
#[inline]
|
||||
pub fn physical_device(&self) -> PhysicalDevice<'a> {
|
||||
self.physical_device
|
||||
}
|
||||
|
||||
/// Returns the identifier of this memory heap within the physical device.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns the size in bytes on this heap.
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
self.physical_device.infos().memory.memoryHeaps[self.id as usize].size as usize
|
||||
}
|
||||
|
||||
/// Returns true if the heap is local to the GPU.
|
||||
#[inline]
|
||||
pub fn is_device_local(&self) -> bool {
|
||||
let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags;
|
||||
(flags & vk::MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if the heap is multi-instance enabled, that is allocation from such
|
||||
/// heap will replicate to each physical-device's instance of heap.
|
||||
#[inline]
|
||||
pub fn is_multi_instance(&self) -> bool {
|
||||
let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags;
|
||||
(flags & vk::MEMORY_HEAP_MULTI_INSTANCE_BIT) != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for all the memory heaps available on a physical device.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryHeapsIter<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
current_id: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for MemoryHeapsIter<'a> {
|
||||
type Item = MemoryHeap<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<MemoryHeap<'a>> {
|
||||
if self.current_id >= self.physical_device.infos().memory.memoryHeapCount {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = MemoryHeap {
|
||||
physical_device: self.physical_device,
|
||||
id: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.physical_device.infos().memory.memoryHeapCount;
|
||||
let remain = (len - self.current_id) as usize;
|
||||
(remain, Some(remain))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for MemoryHeapsIter<'a> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::instance;
|
||||
|
@ -16,10 +16,10 @@ use std::vec::IntoIter;
|
||||
use crate::check_errors;
|
||||
use crate::instance::loader;
|
||||
use crate::instance::loader::LoadingError;
|
||||
use crate::version::Version;
|
||||
use crate::vk;
|
||||
use crate::Error;
|
||||
use crate::OomError;
|
||||
use crate::Version;
|
||||
|
||||
/// Queries the list of layers that are available when creating an instance.
|
||||
///
|
||||
|
@ -21,11 +21,15 @@
|
||||
//! By default vulkano will use the `auto_loader()` function, which tries to automatically load
|
||||
//! a Vulkan implementation from the system.
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::vk;
|
||||
use crate::OomError;
|
||||
use crate::SafeDeref;
|
||||
use crate::Version;
|
||||
use lazy_static::lazy_static;
|
||||
use shared_library;
|
||||
use std::error;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
@ -38,11 +42,7 @@ pub unsafe trait Loader {
|
||||
/// Calls the `vkGetInstanceProcAddr` function. The parameters are the same.
|
||||
///
|
||||
/// The returned function must stay valid for as long as `self` is alive.
|
||||
fn get_instance_proc_addr(
|
||||
&self,
|
||||
instance: vk::Instance,
|
||||
name: *const c_char,
|
||||
) -> extern "system" fn() -> ();
|
||||
fn get_instance_proc_addr(&self, instance: vk::Instance, name: *const c_char) -> *const c_void;
|
||||
}
|
||||
|
||||
unsafe impl<T> Loader for T
|
||||
@ -51,11 +51,7 @@ where
|
||||
T::Target: Loader,
|
||||
{
|
||||
#[inline]
|
||||
fn get_instance_proc_addr(
|
||||
&self,
|
||||
instance: vk::Instance,
|
||||
name: *const c_char,
|
||||
) -> extern "system" fn() -> () {
|
||||
fn get_instance_proc_addr(&self, instance: vk::Instance, name: *const c_char) -> *const c_void {
|
||||
(**self).get_instance_proc_addr(instance, name)
|
||||
}
|
||||
}
|
||||
@ -63,10 +59,8 @@ where
|
||||
/// Implementation of `Loader` that loads Vulkan from a dynamic library.
|
||||
pub struct DynamicLibraryLoader {
|
||||
vk_lib: shared_library::dynamic_library::DynamicLibrary,
|
||||
get_proc_addr: extern "system" fn(
|
||||
instance: vk::Instance,
|
||||
pName: *const c_char,
|
||||
) -> extern "system" fn() -> (),
|
||||
get_proc_addr:
|
||||
extern "system" fn(instance: vk::Instance, pName: *const c_char) -> *const c_void,
|
||||
}
|
||||
|
||||
impl DynamicLibraryLoader {
|
||||
@ -100,11 +94,7 @@ impl DynamicLibraryLoader {
|
||||
|
||||
unsafe impl Loader for DynamicLibraryLoader {
|
||||
#[inline]
|
||||
fn get_instance_proc_addr(
|
||||
&self,
|
||||
instance: vk::Instance,
|
||||
name: *const c_char,
|
||||
) -> extern "system" fn() -> () {
|
||||
fn get_instance_proc_addr(&self, instance: vk::Instance, name: *const c_char) -> *const c_void {
|
||||
(self.get_proc_addr)(instance, name)
|
||||
}
|
||||
}
|
||||
@ -137,13 +127,42 @@ impl<L> FunctionPointers<L> {
|
||||
&self.entry_points
|
||||
}
|
||||
|
||||
/// Returns the highest Vulkan version that is supported for instances.
|
||||
pub fn api_version(&self) -> Result<Version, OomError>
|
||||
where
|
||||
L: Loader,
|
||||
{
|
||||
// Per the Vulkan spec:
|
||||
// If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a
|
||||
// Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion
|
||||
// to determine the version of Vulkan.
|
||||
unsafe {
|
||||
let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0");
|
||||
let func = self.get_instance_proc_addr(0, name.as_ptr());
|
||||
|
||||
if func.is_null() {
|
||||
Ok(Version {
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
})
|
||||
} else {
|
||||
type Pfn = extern "system" fn(pApiVersion: *mut u32) -> vk::Result;
|
||||
let func: Pfn = mem::transmute(func);
|
||||
let mut api_version = 0;
|
||||
check_errors(func(&mut api_version))?;
|
||||
Ok(Version::from_vulkan_version(api_version))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls `get_instance_proc_addr` on the underlying loader.
|
||||
#[inline]
|
||||
pub fn get_instance_proc_addr(
|
||||
&self,
|
||||
instance: vk::Instance,
|
||||
name: *const c_char,
|
||||
) -> extern "system" fn() -> ()
|
||||
) -> *const c_void
|
||||
where
|
||||
L: Loader,
|
||||
{
|
||||
|
@ -111,27 +111,27 @@ pub use self::extensions::RawInstanceExtensions;
|
||||
pub use self::instance::ApplicationInfo;
|
||||
pub use self::instance::Instance;
|
||||
pub use self::instance::InstanceCreationError;
|
||||
pub use self::instance::MemoryHeap;
|
||||
pub use self::instance::MemoryHeapsIter;
|
||||
pub use self::instance::MemoryType;
|
||||
pub use self::instance::MemoryTypesIter;
|
||||
pub use self::instance::PhysicalDevice;
|
||||
pub use self::instance::PhysicalDeviceType;
|
||||
pub use self::instance::PhysicalDevicesIter;
|
||||
pub use self::instance::QueueFamiliesIter;
|
||||
pub use self::instance::QueueFamily;
|
||||
pub use self::layers::layers_list;
|
||||
pub use self::layers::LayerProperties;
|
||||
pub use self::layers::LayersIterator;
|
||||
pub use self::layers::LayersListError;
|
||||
pub use self::limits::Limits;
|
||||
pub use self::loader::LoadingError;
|
||||
pub use self::physical_device::MemoryHeap;
|
||||
pub use self::physical_device::MemoryHeapsIter;
|
||||
pub use self::physical_device::MemoryType;
|
||||
pub use self::physical_device::MemoryTypesIter;
|
||||
pub use self::physical_device::PhysicalDevice;
|
||||
pub use self::physical_device::PhysicalDeviceType;
|
||||
pub use self::physical_device::PhysicalDevicesIter;
|
||||
pub use self::physical_device::QueueFamiliesIter;
|
||||
pub use self::physical_device::QueueFamily;
|
||||
pub use crate::version::Version;
|
||||
|
||||
pub mod debug;
|
||||
pub mod loader;
|
||||
|
||||
mod extensions;
|
||||
mod instance;
|
||||
mod layers;
|
||||
mod limits;
|
||||
pub mod loader;
|
||||
mod physical_device;
|
||||
|
891
vulkano/src/instance/physical_device.rs
Normal file
891
vulkano/src/instance/physical_device.rs
Normal file
@ -0,0 +1,891 @@
|
||||
// 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 crate::check_errors;
|
||||
use crate::features::{Features, FeaturesFfi};
|
||||
use crate::instance::limits::Limits;
|
||||
use crate::instance::{Instance, InstanceCreationError, RawInstanceExtensions};
|
||||
use crate::sync::PipelineStage;
|
||||
use crate::vk;
|
||||
use crate::Version;
|
||||
use crate::VulkanObject;
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::CString;
|
||||
use std::hash::Hash;
|
||||
use std::mem;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(super) fn init_physical_devices(
|
||||
instance: vk::Instance,
|
||||
vk: &vk::InstancePointers,
|
||||
extensions: &RawInstanceExtensions,
|
||||
) -> Result<Vec<PhysicalDeviceInfos>, InstanceCreationError> {
|
||||
let physical_devices: Vec<vk::PhysicalDevice> = unsafe {
|
||||
let mut num = 0;
|
||||
check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, ptr::null_mut()))?;
|
||||
|
||||
let mut devices = Vec::with_capacity(num as usize);
|
||||
check_errors(vk.EnumeratePhysicalDevices(instance, &mut num, devices.as_mut_ptr()))?;
|
||||
devices.set_len(num as usize);
|
||||
devices
|
||||
};
|
||||
|
||||
let vk_khr_get_physical_device_properties2 =
|
||||
CString::new(b"VK_KHR_get_physical_device_properties2".to_vec()).unwrap();
|
||||
|
||||
// Getting the properties of all physical devices.
|
||||
// If possible, we use VK_KHR_get_physical_device_properties2.
|
||||
let physical_devices = if extensions
|
||||
.iter()
|
||||
.any(|v| *v == vk_khr_get_physical_device_properties2)
|
||||
{
|
||||
init_physical_devices_inner2(&vk, physical_devices, &extensions)
|
||||
} else {
|
||||
init_physical_devices_inner(&vk, physical_devices)
|
||||
};
|
||||
|
||||
Ok(physical_devices)
|
||||
}
|
||||
|
||||
/// Initialize all physical devices
|
||||
fn init_physical_devices_inner(
|
||||
vk: &vk::InstancePointers,
|
||||
physical_devices: Vec<vk::PhysicalDevice>,
|
||||
) -> Vec<PhysicalDeviceInfos> {
|
||||
let mut output = Vec::with_capacity(physical_devices.len());
|
||||
|
||||
for device in physical_devices.into_iter() {
|
||||
let properties: vk::PhysicalDeviceProperties = unsafe {
|
||||
let mut output = MaybeUninit::uninit();
|
||||
vk.GetPhysicalDeviceProperties(device, output.as_mut_ptr());
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
let queue_families = unsafe {
|
||||
let mut num = 0;
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, ptr::null_mut());
|
||||
|
||||
let mut families = Vec::with_capacity(num as usize);
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties(device, &mut num, families.as_mut_ptr());
|
||||
families.set_len(num as usize);
|
||||
families
|
||||
};
|
||||
|
||||
let memory: vk::PhysicalDeviceMemoryProperties = unsafe {
|
||||
let mut output = MaybeUninit::uninit();
|
||||
vk.GetPhysicalDeviceMemoryProperties(device, output.as_mut_ptr());
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
let available_features: vk::PhysicalDeviceFeatures = unsafe {
|
||||
let mut output = MaybeUninit::uninit();
|
||||
vk.GetPhysicalDeviceFeatures(device, output.as_mut_ptr());
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
output.push(PhysicalDeviceInfos {
|
||||
device,
|
||||
properties,
|
||||
extended_properties: PhysicalDeviceExtendedProperties::empty(),
|
||||
memory,
|
||||
queue_families,
|
||||
available_features: Features::from(available_features),
|
||||
});
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
/// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2
|
||||
/// TODO: Query extension-specific physical device properties, once a new instance extension is supported.
|
||||
fn init_physical_devices_inner2(
|
||||
vk: &vk::InstancePointers,
|
||||
physical_devices: Vec<vk::PhysicalDevice>,
|
||||
extensions: &RawInstanceExtensions,
|
||||
) -> Vec<PhysicalDeviceInfos> {
|
||||
let mut output = Vec::with_capacity(physical_devices.len());
|
||||
|
||||
for device in physical_devices.into_iter() {
|
||||
let mut extended_properties = PhysicalDeviceExtendedProperties::empty();
|
||||
|
||||
let properties: vk::PhysicalDeviceProperties = unsafe {
|
||||
let mut subgroup_properties = vk::PhysicalDeviceSubgroupProperties {
|
||||
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES,
|
||||
pNext: ptr::null_mut(),
|
||||
subgroupSize: 0,
|
||||
supportedStages: 0,
|
||||
supportedOperations: 0,
|
||||
quadOperationsInAllStages: 0,
|
||||
};
|
||||
|
||||
let mut output = vk::PhysicalDeviceProperties2KHR {
|
||||
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
|
||||
pNext: &mut subgroup_properties,
|
||||
properties: mem::zeroed(),
|
||||
};
|
||||
|
||||
vk.GetPhysicalDeviceProperties2KHR(device, &mut output);
|
||||
|
||||
extended_properties = PhysicalDeviceExtendedProperties {
|
||||
subgroup_size: Some(subgroup_properties.subgroupSize),
|
||||
|
||||
..extended_properties
|
||||
};
|
||||
|
||||
output.properties
|
||||
};
|
||||
|
||||
let queue_families = unsafe {
|
||||
let mut num = 0;
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties2KHR(device, &mut num, ptr::null_mut());
|
||||
|
||||
let mut families = (0..num)
|
||||
.map(|_| vk::QueueFamilyProperties2KHR {
|
||||
sType: vk::STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR,
|
||||
pNext: ptr::null_mut(),
|
||||
queueFamilyProperties: mem::zeroed(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties2KHR(device, &mut num, families.as_mut_ptr());
|
||||
families
|
||||
.into_iter()
|
||||
.map(|family| family.queueFamilyProperties)
|
||||
.collect()
|
||||
};
|
||||
|
||||
let memory: vk::PhysicalDeviceMemoryProperties = unsafe {
|
||||
let mut output = vk::PhysicalDeviceMemoryProperties2KHR {
|
||||
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR,
|
||||
pNext: ptr::null_mut(),
|
||||
memoryProperties: mem::zeroed(),
|
||||
};
|
||||
vk.GetPhysicalDeviceMemoryProperties2KHR(device, &mut output);
|
||||
output.memoryProperties
|
||||
};
|
||||
|
||||
let available_features: Features = unsafe {
|
||||
let mut output = FeaturesFfi::new();
|
||||
let ptr = FeaturesFfi::mut_base_ptr(&mut output) as *mut _;
|
||||
vk.GetPhysicalDeviceFeatures2KHR(device, ptr);
|
||||
Features::from(&output.main)
|
||||
};
|
||||
|
||||
output.push(PhysicalDeviceInfos {
|
||||
device,
|
||||
properties,
|
||||
extended_properties,
|
||||
memory,
|
||||
queue_families,
|
||||
available_features,
|
||||
});
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub(super) struct PhysicalDeviceInfos {
|
||||
device: vk::PhysicalDevice,
|
||||
properties: vk::PhysicalDeviceProperties,
|
||||
extended_properties: PhysicalDeviceExtendedProperties,
|
||||
queue_families: Vec<vk::QueueFamilyProperties>,
|
||||
memory: vk::PhysicalDeviceMemoryProperties,
|
||||
available_features: Features,
|
||||
}
|
||||
|
||||
/// Represents additional information related to Physical Devices fetched from
|
||||
/// `vkGetPhysicalDeviceProperties` call. Certain features available only when
|
||||
/// appropriate `Instance` extensions enabled. The core extension required
|
||||
/// for this features is `InstanceExtensions::khr_get_physical_device_properties2`
|
||||
///
|
||||
/// TODO: Only a small subset of available properties(https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties2.html) is implemented at this moment.
|
||||
pub struct PhysicalDeviceExtendedProperties {
|
||||
subgroup_size: Option<u32>,
|
||||
}
|
||||
|
||||
impl PhysicalDeviceExtendedProperties {
|
||||
pub(super) fn empty() -> Self {
|
||||
Self {
|
||||
subgroup_size: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The default number of invocations in each subgroup
|
||||
///
|
||||
/// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html for details
|
||||
#[inline]
|
||||
pub fn subgroup_size(&self) -> &Option<u32> {
|
||||
&self.subgroup_size
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents one of the available devices on this machine.
|
||||
///
|
||||
/// This struct simply contains a pointer to an instance and a number representing the physical
|
||||
/// device. You are therefore encouraged to pass this around by value instead of by reference.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use vulkano::instance::Instance;
|
||||
/// # use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// for physical_device in PhysicalDevice::enumerate(&instance) {
|
||||
/// print_infos(physical_device);
|
||||
/// }
|
||||
///
|
||||
/// fn print_infos(dev: PhysicalDevice) {
|
||||
/// println!("Name: {}", dev.name());
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PhysicalDevice<'a> {
|
||||
instance: &'a Arc<Instance>,
|
||||
device: usize,
|
||||
}
|
||||
|
||||
impl<'a> PhysicalDevice<'a> {
|
||||
/// Returns an iterator that enumerates the physical devices available.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use vulkano::instance::Instance;
|
||||
/// # use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// for physical_device in PhysicalDevice::enumerate(&instance) {
|
||||
/// println!("Available device: {}", physical_device.name());
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn enumerate(instance: &'a Arc<Instance>) -> PhysicalDevicesIter<'a> {
|
||||
PhysicalDevicesIter {
|
||||
instance,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a physical device from its index. Returns `None` if out of range.
|
||||
///
|
||||
/// Indices range from 0 to the number of devices.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use vulkano::instance::Instance;
|
||||
/// use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_index(instance: &'a Arc<Instance>, index: usize) -> Option<PhysicalDevice<'a>> {
|
||||
if instance.physical_devices.len() > index {
|
||||
Some(PhysicalDevice {
|
||||
instance,
|
||||
device: index,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the instance corresponding to this physical device.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// fn do_something(physical_device: PhysicalDevice) {
|
||||
/// let _loaded_extensions = physical_device.instance().loaded_extensions();
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn instance(&self) -> &'a Arc<Instance> {
|
||||
&self.instance
|
||||
}
|
||||
|
||||
/// Returns the index of the physical device in the physical devices list.
|
||||
///
|
||||
/// This index never changes and can be used later to retrieve a `PhysicalDevice` from an
|
||||
/// instance and an index.
|
||||
#[inline]
|
||||
pub fn index(&self) -> usize {
|
||||
self.device
|
||||
}
|
||||
|
||||
/// Returns the human-readable name of the device.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
unsafe {
|
||||
let val = &self.infos().properties.deviceName;
|
||||
let val = CStr::from_ptr(val.as_ptr());
|
||||
val.to_str()
|
||||
.expect("physical device name contained non-UTF8 characters")
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the type of the device.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use vulkano::instance::Instance;
|
||||
/// # use vulkano::instance::InstanceExtensions;
|
||||
/// use vulkano::instance::PhysicalDevice;
|
||||
///
|
||||
/// # let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
|
||||
/// for physical_device in PhysicalDevice::enumerate(&instance) {
|
||||
/// println!("Available device: {} (type: {:?})",
|
||||
/// physical_device.name(), physical_device.ty());
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn ty(&self) -> PhysicalDeviceType {
|
||||
match self.instance.physical_devices[self.device]
|
||||
.properties
|
||||
.deviceType
|
||||
{
|
||||
vk::PHYSICAL_DEVICE_TYPE_OTHER => PhysicalDeviceType::Other,
|
||||
vk::PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => PhysicalDeviceType::IntegratedGpu,
|
||||
vk::PHYSICAL_DEVICE_TYPE_DISCRETE_GPU => PhysicalDeviceType::DiscreteGpu,
|
||||
vk::PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU => PhysicalDeviceType::VirtualGpu,
|
||||
vk::PHYSICAL_DEVICE_TYPE_CPU => PhysicalDeviceType::Cpu,
|
||||
_ => panic!("Unrecognized Vulkan device type"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the version of Vulkan supported by this device.
|
||||
#[inline]
|
||||
pub fn api_version(&self) -> Version {
|
||||
let val = self.infos().properties.apiVersion;
|
||||
Version::from_vulkan_version(val)
|
||||
}
|
||||
|
||||
/// Returns the Vulkan features that are supported by this physical device.
|
||||
#[inline]
|
||||
pub fn supported_features(&self) -> &'a Features {
|
||||
&self.infos().available_features
|
||||
}
|
||||
|
||||
/// Builds an iterator that enumerates all the queue families on this physical device.
|
||||
#[inline]
|
||||
pub fn queue_families(&self) -> QueueFamiliesIter<'a> {
|
||||
QueueFamiliesIter {
|
||||
physical_device: *self,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the queue family with the given index, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn queue_family_by_id(&self, id: u32) -> Option<QueueFamily<'a>> {
|
||||
if (id as usize) < self.infos().queue_families.len() {
|
||||
Some(QueueFamily {
|
||||
physical_device: *self,
|
||||
id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an iterator that enumerates all the memory types on this physical device.
|
||||
#[inline]
|
||||
pub fn memory_types(&self) -> MemoryTypesIter<'a> {
|
||||
MemoryTypesIter {
|
||||
physical_device: *self,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the memory type with the given index, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn memory_type_by_id(&self, id: u32) -> Option<MemoryType<'a>> {
|
||||
if id < self.infos().memory.memoryTypeCount {
|
||||
Some(MemoryType {
|
||||
physical_device: *self,
|
||||
id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an iterator that enumerates all the memory heaps on this physical device.
|
||||
#[inline]
|
||||
pub fn memory_heaps(&self) -> MemoryHeapsIter<'a> {
|
||||
MemoryHeapsIter {
|
||||
physical_device: *self,
|
||||
current_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the memory heap with the given index, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn memory_heap_by_id(&self, id: u32) -> Option<MemoryHeap<'a>> {
|
||||
if id < self.infos().memory.memoryHeapCount {
|
||||
Some(MemoryHeap {
|
||||
physical_device: *self,
|
||||
id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Gives access to the limits of the physical device.
|
||||
///
|
||||
/// This function should be zero-cost in release mode. It only exists to not pollute the
|
||||
/// namespace of `PhysicalDevice` with all the limits-related getters.
|
||||
#[inline]
|
||||
pub fn limits(&self) -> Limits<'a> {
|
||||
Limits::from_vk_limits(&self.infos().properties.limits)
|
||||
}
|
||||
|
||||
/// Returns an opaque number representing the version of the driver of this device.
|
||||
///
|
||||
/// The meaning of this number is implementation-specific. It can be used in bug reports, for
|
||||
/// example.
|
||||
#[inline]
|
||||
pub fn driver_version(&self) -> u32 {
|
||||
self.infos().properties.driverVersion
|
||||
}
|
||||
|
||||
/// Returns the PCI ID of the device.
|
||||
#[inline]
|
||||
pub fn pci_device_id(&self) -> u32 {
|
||||
self.infos().properties.deviceID
|
||||
}
|
||||
|
||||
/// Returns the PCI ID of the vendor.
|
||||
#[inline]
|
||||
pub fn pci_vendor_id(&self) -> u32 {
|
||||
self.infos().properties.vendorID
|
||||
}
|
||||
|
||||
/// Returns a unique identifier for the device.
|
||||
///
|
||||
/// Can be stored in a configuration file, so that you can retrieve the device again the next
|
||||
/// time the program is run.
|
||||
#[inline]
|
||||
pub fn uuid(&self) -> &[u8; 16] {
|
||||
// must be equal to vk::UUID_SIZE
|
||||
&self.infos().properties.pipelineCacheUUID
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extended_properties(&self) -> &PhysicalDeviceExtendedProperties {
|
||||
&self.infos().extended_properties
|
||||
}
|
||||
|
||||
// Internal function to make it easier to get the infos of this device.
|
||||
#[inline]
|
||||
fn infos(&self) -> &'a PhysicalDeviceInfos {
|
||||
&self.instance.physical_devices[self.device]
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> VulkanObject for PhysicalDevice<'a> {
|
||||
type Object = vk::PhysicalDevice;
|
||||
|
||||
const TYPE: vk::ObjectType = vk::OBJECT_TYPE_PHYSICAL_DEVICE;
|
||||
|
||||
#[inline]
|
||||
fn internal_object(&self) -> vk::PhysicalDevice {
|
||||
self.infos().device
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for all the physical devices available on hardware.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PhysicalDevicesIter<'a> {
|
||||
instance: &'a Arc<Instance>,
|
||||
current_id: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PhysicalDevicesIter<'a> {
|
||||
type Item = PhysicalDevice<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<PhysicalDevice<'a>> {
|
||||
if self.current_id >= self.instance.physical_devices.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = PhysicalDevice {
|
||||
instance: self.instance,
|
||||
device: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.instance.physical_devices.len() - self.current_id;
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for PhysicalDevicesIter<'a> {}
|
||||
|
||||
/// Type of a physical device.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
#[repr(u32)]
|
||||
pub enum PhysicalDeviceType {
|
||||
/// The device is an integrated GPU.
|
||||
IntegratedGpu = 1,
|
||||
/// The device is a discrete GPU.
|
||||
DiscreteGpu = 2,
|
||||
/// The device is a virtual GPU.
|
||||
VirtualGpu = 3,
|
||||
/// The device is a CPU.
|
||||
Cpu = 4,
|
||||
/// The device is something else.
|
||||
Other = 0,
|
||||
}
|
||||
|
||||
/// Represents a queue family in a physical device.
|
||||
///
|
||||
/// A queue family is group of one or multiple queues. All queues of one family have the same
|
||||
/// characteristics.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct QueueFamily<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl<'a> QueueFamily<'a> {
|
||||
/// Returns the physical device associated to this queue family.
|
||||
#[inline]
|
||||
pub fn physical_device(&self) -> PhysicalDevice<'a> {
|
||||
self.physical_device
|
||||
}
|
||||
|
||||
/// Returns the identifier of this queue family within the physical device.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns the number of queues that belong to this family.
|
||||
///
|
||||
/// Guaranteed to be at least 1 (or else that family wouldn't exist).
|
||||
#[inline]
|
||||
pub fn queues_count(&self) -> usize {
|
||||
self.physical_device.infos().queue_families[self.id as usize].queueCount as usize
|
||||
}
|
||||
|
||||
/// If timestamps are supported, returns the number of bits supported by timestamp operations.
|
||||
/// The returned value will be in the range 36..64.
|
||||
/// If timestamps are not supported, returns None.
|
||||
#[inline]
|
||||
pub fn timestamp_valid_bits(&self) -> Option<u32> {
|
||||
let value =
|
||||
self.physical_device.infos().queue_families[self.id as usize].timestampValidBits;
|
||||
if value == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the minimum granularity supported for image transfers in terms
|
||||
/// of `[width, height, depth]`
|
||||
#[inline]
|
||||
pub fn min_image_transfer_granularity(&self) -> [u32; 3] {
|
||||
let ref granularity = self.physical_device.infos().queue_families[self.id as usize]
|
||||
.minImageTransferGranularity;
|
||||
[granularity.width, granularity.height, granularity.depth]
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute graphics operations.
|
||||
#[inline]
|
||||
pub fn supports_graphics(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_GRAPHICS_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute compute operations.
|
||||
#[inline]
|
||||
pub fn supports_compute(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_COMPUTE_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute transfer operations.
|
||||
/// > **Note**: While all queues that can perform graphics or compute operations can implicitly perform
|
||||
/// > transfer operations, graphics & compute queues only optionally indicate support for tranfers.
|
||||
/// > Many discrete cards will have one queue family that exclusively sets the VK_QUEUE_TRANSFER_BIT
|
||||
/// > to indicate a special relationship with the DMA module and more efficient transfers.
|
||||
#[inline]
|
||||
pub fn explicitly_supports_transfers(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_TRANSFER_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if queues of this family can execute sparse resources binding operations.
|
||||
#[inline]
|
||||
pub fn supports_sparse_binding(&self) -> bool {
|
||||
(self.flags() & vk::QUEUE_SPARSE_BINDING_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if the queues of this family support a particular pipeline stage.
|
||||
#[inline]
|
||||
pub fn supports_stage(&self, stage: PipelineStage) -> bool {
|
||||
(self.flags() & stage.required_queue_flags()) != 0
|
||||
}
|
||||
|
||||
/// Internal utility function that returns the flags of this queue family.
|
||||
#[inline]
|
||||
fn flags(&self) -> u32 {
|
||||
self.physical_device.infos().queue_families[self.id as usize].queueFlags
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for QueueFamily<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
&& self.physical_device.internal_object() == other.physical_device.internal_object()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Eq for QueueFamily<'a> {}
|
||||
|
||||
/// Iterator for all the queue families available on a physical device.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct QueueFamiliesIter<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
current_id: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for QueueFamiliesIter<'a> {
|
||||
type Item = QueueFamily<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<QueueFamily<'a>> {
|
||||
if self.current_id as usize >= self.physical_device.infos().queue_families.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = QueueFamily {
|
||||
physical_device: self.physical_device,
|
||||
id: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.physical_device.infos().queue_families.len();
|
||||
let remain = len - self.current_id as usize;
|
||||
(remain, Some(remain))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for QueueFamiliesIter<'a> {}
|
||||
|
||||
/// Represents a memory type in a physical device.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MemoryType<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl<'a> MemoryType<'a> {
|
||||
/// Returns the physical device associated to this memory type.
|
||||
#[inline]
|
||||
pub fn physical_device(&self) -> PhysicalDevice<'a> {
|
||||
self.physical_device
|
||||
}
|
||||
|
||||
/// Returns the identifier of this memory type within the physical device.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns the heap that corresponds to this memory type.
|
||||
#[inline]
|
||||
pub fn heap(&self) -> MemoryHeap<'a> {
|
||||
let heap_id = self.physical_device.infos().memory.memoryTypes[self.id as usize].heapIndex;
|
||||
MemoryHeap {
|
||||
physical_device: self.physical_device,
|
||||
id: heap_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the memory type is located on the device, which means that it's the most
|
||||
/// efficient for GPU accesses.
|
||||
#[inline]
|
||||
pub fn is_device_local(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if the memory type can be accessed by the host.
|
||||
#[inline]
|
||||
pub fn is_host_visible(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if modifications made by the host or the GPU on this memory type are
|
||||
/// instantaneously visible to the other party. False means that changes have to be flushed.
|
||||
///
|
||||
/// You don't need to worry about this, as this library handles that for you.
|
||||
#[inline]
|
||||
pub fn is_host_coherent(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if memory of this memory type is cached by the host. Host memory accesses to
|
||||
/// cached memory is faster than for uncached memory. However you are not guaranteed that it
|
||||
/// is coherent.
|
||||
#[inline]
|
||||
pub fn is_host_cached(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_HOST_CACHED_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if allocations made to this memory type is lazy.
|
||||
///
|
||||
/// This means that no actual allocation is performed. Instead memory is automatically
|
||||
/// allocated by the Vulkan implementation.
|
||||
///
|
||||
/// Memory of this type can only be used on images created with a certain flag. Memory of this
|
||||
/// type is never host-visible.
|
||||
#[inline]
|
||||
pub fn is_lazily_allocated(&self) -> bool {
|
||||
(self.flags() & vk::MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0
|
||||
}
|
||||
|
||||
/// Internal utility function that returns the flags of this queue family.
|
||||
#[inline]
|
||||
fn flags(&self) -> u32 {
|
||||
self.physical_device.infos().memory.memoryTypes[self.id as usize].propertyFlags
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for all the memory types available on a physical device.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryTypesIter<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
current_id: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for MemoryTypesIter<'a> {
|
||||
type Item = MemoryType<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<MemoryType<'a>> {
|
||||
if self.current_id >= self.physical_device.infos().memory.memoryTypeCount {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = MemoryType {
|
||||
physical_device: self.physical_device,
|
||||
id: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.physical_device.infos().memory.memoryTypeCount;
|
||||
let remain = (len - self.current_id) as usize;
|
||||
(remain, Some(remain))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for MemoryTypesIter<'a> {}
|
||||
|
||||
/// Represents a memory heap in a physical device.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MemoryHeap<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl<'a> MemoryHeap<'a> {
|
||||
/// Returns the physical device associated to this memory heap.
|
||||
#[inline]
|
||||
pub fn physical_device(&self) -> PhysicalDevice<'a> {
|
||||
self.physical_device
|
||||
}
|
||||
|
||||
/// Returns the identifier of this memory heap within the physical device.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns the size in bytes on this heap.
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
self.physical_device.infos().memory.memoryHeaps[self.id as usize].size as usize
|
||||
}
|
||||
|
||||
/// Returns true if the heap is local to the GPU.
|
||||
#[inline]
|
||||
pub fn is_device_local(&self) -> bool {
|
||||
let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags;
|
||||
(flags & vk::MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0
|
||||
}
|
||||
|
||||
/// Returns true if the heap is multi-instance enabled, that is allocation from such
|
||||
/// heap will replicate to each physical-device's instance of heap.
|
||||
#[inline]
|
||||
pub fn is_multi_instance(&self) -> bool {
|
||||
let flags = self.physical_device.infos().memory.memoryHeaps[self.id as usize].flags;
|
||||
(flags & vk::MEMORY_HEAP_MULTI_INSTANCE_BIT) != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for all the memory heaps available on a physical device.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryHeapsIter<'a> {
|
||||
physical_device: PhysicalDevice<'a>,
|
||||
current_id: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for MemoryHeapsIter<'a> {
|
||||
type Item = MemoryHeap<'a>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<MemoryHeap<'a>> {
|
||||
if self.current_id >= self.physical_device.infos().memory.memoryHeapCount {
|
||||
return None;
|
||||
}
|
||||
|
||||
let dev = MemoryHeap {
|
||||
physical_device: self.physical_device,
|
||||
id: self.current_id,
|
||||
};
|
||||
|
||||
self.current_id += 1;
|
||||
Some(dev)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.physical_device.infos().memory.memoryHeapCount;
|
||||
let remain = (len - self.current_id) as usize;
|
||||
(remain, Some(remain))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for MemoryHeapsIter<'a> {}
|
@ -70,6 +70,7 @@ use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::sync::MutexGuard;
|
||||
pub use version::Version;
|
||||
|
||||
#[macro_use]
|
||||
mod tests;
|
||||
|
@ -9,11 +9,10 @@
|
||||
|
||||
// The `Version` object is reexported from the `instance` module.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
||||
/// Represents an API version of Vulkan.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Version {
|
||||
/// Major version number.
|
||||
pub major: u16,
|
||||
@ -35,29 +34,6 @@ impl fmt::Display for Version {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Version {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Version {
|
||||
fn cmp(&self, other: &Version) -> Ordering {
|
||||
match self.major.cmp(&other.major) {
|
||||
Ordering::Equal => (),
|
||||
o => return o,
|
||||
};
|
||||
|
||||
match self.minor.cmp(&other.minor) {
|
||||
Ordering::Equal => (),
|
||||
o => return o,
|
||||
};
|
||||
|
||||
self.patch.cmp(&other.patch)
|
||||
}
|
||||
}
|
||||
|
||||
impl Version {
|
||||
/// Turns a version number given by Vulkan into a `Version` struct.
|
||||
#[inline]
|
||||
|
Loading…
Reference in New Issue
Block a user