use std::{convert::TryInto as _, ffi::CStr};
use erupt::{
extensions::{
ext_descriptor_indexing::EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
ext_scalar_block_layout::EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME,
google_display_timing::GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
khr_acceleration_structure::{self as acc, KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME},
khr_buffer_device_address::KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
khr_deferred_host_operations::KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME,
khr_dynamic_rendering::KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
khr_ray_tracing_pipeline::{self as rt, KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME},
khr_swapchain::KHR_SWAPCHAIN_EXTENSION_NAME,
},
vk1_0, vk1_1, vk1_2, vk1_3, DeviceLoader, ExtendableFrom, LoaderError, ObjectHandle,
};
use hashbrown::HashMap;
use smallvec::SmallVec;
use crate::{
arith_gt, assert_object, out_of_host_memory,
physical::*,
queue::{Family, FamilyInfo, Queue, QueueId, QueuesQuery},
CreateDeviceError, OutOfMemory,
};
use super::{convert::from_erupt, device::Device, graphics::Graphics, unexpected_result};
#[derive(Clone, Debug)]
pub(super) struct Properties {
pub extension: SmallVec<[vk1_0::ExtensionProperties; 8]>,
pub family: SmallVec<[vk1_0::QueueFamilyProperties; 8]>,
pub memory: vk1_0::PhysicalDeviceMemoryProperties,
pub v10: vk1_0::PhysicalDeviceProperties,
pub v11: vk1_2::PhysicalDeviceVulkan11Properties,
pub v12: vk1_2::PhysicalDeviceVulkan12Properties,
pub v13: vk1_3::PhysicalDeviceVulkan13Properties,
pub acc: acc::PhysicalDeviceAccelerationStructurePropertiesKHR,
pub rt: rt::PhysicalDeviceRayTracingPipelinePropertiesKHR,
}
unsafe impl Sync for Properties {}
unsafe impl Send for Properties {}
#[derive(Clone, Debug)]
pub(super) struct Features {
pub v10: vk1_0::PhysicalDeviceFeatures,
pub v11: vk1_2::PhysicalDeviceVulkan11Features,
pub v12: vk1_2::PhysicalDeviceVulkan12Features,
pub v13: vk1_3::PhysicalDeviceVulkan13Features,
pub acc: acc::PhysicalDeviceAccelerationStructureFeaturesKHR,
pub rt: rt::PhysicalDeviceRayTracingPipelineFeaturesKHR,
}
unsafe impl Sync for Features {}
unsafe impl Send for Features {}
unsafe fn collect_properties_and_features(
physical: vk1_0::PhysicalDevice,
) -> (Properties, Features) {
let graphics = Graphics::get_unchecked();
let extension_properties = graphics
.instance
.enumerate_device_extension_properties(physical, None, None)
.expect("OOM on initialization");
let has_extension = |name| -> bool {
let name = CStr::from_ptr(name);
extension_properties
.iter()
.any(|p| CStr::from_ptr(&p.extension_name[0]) == name)
};
let properties10;
let mut properties11 = vk1_2::PhysicalDeviceVulkan11PropertiesBuilder::new();
let mut properties12 = vk1_2::PhysicalDeviceVulkan12PropertiesBuilder::new();
let mut properties13 = vk1_3::PhysicalDeviceVulkan13PropertiesBuilder::new();
let mut properties_edi = vk1_2::PhysicalDeviceDescriptorIndexingPropertiesBuilder::new();
let mut properties_rt = rt::PhysicalDeviceRayTracingPipelinePropertiesKHRBuilder::new();
let mut properties_acc = acc::PhysicalDeviceAccelerationStructurePropertiesKHRBuilder::new();
let features10;
let mut features11 = vk1_2::PhysicalDeviceVulkan11FeaturesBuilder::new();
let mut features12 = vk1_2::PhysicalDeviceVulkan12FeaturesBuilder::new();
let mut features13 = vk1_3::PhysicalDeviceVulkan13FeaturesBuilder::new();
let mut features_sbl = vk1_2::PhysicalDeviceScalarBlockLayoutFeaturesBuilder::new();
let mut features_edi = vk1_2::PhysicalDeviceDescriptorIndexingFeaturesBuilder::new();
let mut features_bda = vk1_2::PhysicalDeviceBufferDeviceAddressFeaturesBuilder::new();
let mut features_acc = acc::PhysicalDeviceAccelerationStructureFeaturesKHRBuilder::new();
let mut features_rt = rt::PhysicalDeviceRayTracingPipelineFeaturesKHRBuilder::new();
let mut features_dr = vk1_3::PhysicalDeviceDynamicRenderingFeaturesBuilder::new();
if graphics.instance.enabled().vk1_1
|| graphics
.instance
.enabled()
.khr_get_physical_device_properties2
{
let mut properties2 = vk1_1::PhysicalDeviceProperties2Builder::new();
let mut features2 = vk1_1::PhysicalDeviceFeatures2Builder::new();
if graphics.instance.enabled().vk1_1 {
properties2 = properties2.extend_from(&mut properties11);
features2 = features2.extend_from(&mut features11);
}
if graphics.instance.enabled().vk1_2 {
properties2 = properties2.extend_from(&mut properties12);
features2 = features2.extend_from(&mut features12);
}
if graphics.instance.enabled().vk1_3 {
properties2 = properties2.extend_from(&mut properties13);
features2 = features2.extend_from(&mut features13);
}
if !graphics.instance.enabled().vk1_2
&& has_extension(EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME)
{
features2 = features2.extend_from(&mut features_sbl);
}
if !graphics.instance.enabled().vk1_2
&& has_extension(EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)
{
features2 = features2.extend_from(&mut features_edi);
properties2 = properties2.extend_from(&mut properties_edi);
}
if !graphics.instance.enabled().vk1_2
&& has_extension(KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)
{
features2 = features2.extend_from(&mut features_bda);
}
if !graphics.instance.enabled().vk1_3 && has_extension(KHR_DYNAMIC_RENDERING_EXTENSION_NAME)
{
features2 = features2.extend_from(&mut features_dr);
}
if has_extension(KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME) {
properties2 = properties2.extend_from(&mut properties_acc);
features2 = features2.extend_from(&mut features_acc);
}
if has_extension(KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME) {
properties2 = properties2.extend_from(&mut properties_rt);
features2 = features2.extend_from(&mut features_rt);
}
graphics
.instance
.get_physical_device_properties2(physical, &mut properties2);
graphics
.instance
.get_physical_device_features2(physical, &mut features2);
properties10 = properties2.properties;
features10 = features2.features;
} else {
properties10 = graphics.instance.get_physical_device_properties(physical);
features10 = graphics.instance.get_physical_device_features(physical);
}
let family_properties = graphics
.instance
.get_physical_device_queue_family_properties(physical, None);
let memory_properties = graphics
.instance
.get_physical_device_memory_properties(physical);
if !graphics.instance.enabled().vk1_2 && has_extension(EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME) {
features12.scalar_block_layout = features_sbl.scalar_block_layout;
}
if !graphics.instance.enabled().vk1_2 && has_extension(EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME) {
properties12.max_update_after_bind_descriptors_in_all_pools =
properties_edi.max_update_after_bind_descriptors_in_all_pools;
properties12.shader_uniform_buffer_array_non_uniform_indexing_native =
properties_edi.shader_uniform_buffer_array_non_uniform_indexing_native;
properties12.shader_sampled_image_array_non_uniform_indexing_native =
properties_edi.shader_sampled_image_array_non_uniform_indexing_native;
properties12.shader_storage_buffer_array_non_uniform_indexing_native =
properties_edi.shader_storage_buffer_array_non_uniform_indexing_native;
properties12.shader_storage_image_array_non_uniform_indexing_native =
properties_edi.shader_storage_image_array_non_uniform_indexing_native;
properties12.shader_input_attachment_array_non_uniform_indexing_native =
properties_edi.shader_input_attachment_array_non_uniform_indexing_native;
properties12.robust_buffer_access_update_after_bind =
properties_edi.robust_buffer_access_update_after_bind;
properties12.quad_divergent_implicit_lod = properties_edi.quad_divergent_implicit_lod;
properties12.max_per_stage_descriptor_update_after_bind_samplers =
properties_edi.max_per_stage_descriptor_update_after_bind_samplers;
properties12.max_per_stage_descriptor_update_after_bind_uniform_buffers =
properties_edi.max_per_stage_descriptor_update_after_bind_uniform_buffers;
properties12.max_per_stage_descriptor_update_after_bind_storage_buffers =
properties_edi.max_per_stage_descriptor_update_after_bind_storage_buffers;
properties12.max_per_stage_descriptor_update_after_bind_sampled_images =
properties_edi.max_per_stage_descriptor_update_after_bind_sampled_images;
properties12.max_per_stage_descriptor_update_after_bind_storage_images =
properties_edi.max_per_stage_descriptor_update_after_bind_storage_images;
properties12.max_per_stage_descriptor_update_after_bind_input_attachments =
properties_edi.max_per_stage_descriptor_update_after_bind_input_attachments;
properties12.max_per_stage_update_after_bind_resources =
properties_edi.max_per_stage_update_after_bind_resources;
properties12.max_descriptor_set_update_after_bind_samplers =
properties_edi.max_descriptor_set_update_after_bind_samplers;
properties12.max_descriptor_set_update_after_bind_uniform_buffers =
properties_edi.max_descriptor_set_update_after_bind_uniform_buffers;
properties12.max_descriptor_set_update_after_bind_uniform_buffers_dynamic =
properties_edi.max_descriptor_set_update_after_bind_uniform_buffers_dynamic;
properties12.max_descriptor_set_update_after_bind_storage_buffers =
properties_edi.max_descriptor_set_update_after_bind_storage_buffers;
properties12.max_descriptor_set_update_after_bind_storage_buffers_dynamic =
properties_edi.max_descriptor_set_update_after_bind_storage_buffers_dynamic;
properties12.max_descriptor_set_update_after_bind_sampled_images =
properties_edi.max_descriptor_set_update_after_bind_sampled_images;
properties12.max_descriptor_set_update_after_bind_storage_images =
properties_edi.max_descriptor_set_update_after_bind_storage_images;
properties12.max_descriptor_set_update_after_bind_input_attachments =
properties_edi.max_descriptor_set_update_after_bind_input_attachments;
features12.shader_input_attachment_array_dynamic_indexing =
features_edi.shader_input_attachment_array_dynamic_indexing;
features12.shader_uniform_texel_buffer_array_dynamic_indexing =
features_edi.shader_uniform_texel_buffer_array_dynamic_indexing;
features12.shader_storage_texel_buffer_array_dynamic_indexing =
features_edi.shader_storage_texel_buffer_array_dynamic_indexing;
features12.shader_uniform_buffer_array_non_uniform_indexing =
features_edi.shader_uniform_buffer_array_non_uniform_indexing;
features12.shader_sampled_image_array_non_uniform_indexing =
features_edi.shader_sampled_image_array_non_uniform_indexing;
features12.shader_storage_buffer_array_non_uniform_indexing =
features_edi.shader_storage_buffer_array_non_uniform_indexing;
features12.shader_storage_image_array_non_uniform_indexing =
features_edi.shader_storage_image_array_non_uniform_indexing;
features12.shader_input_attachment_array_non_uniform_indexing =
features_edi.shader_input_attachment_array_non_uniform_indexing;
features12.shader_uniform_texel_buffer_array_non_uniform_indexing =
features_edi.shader_uniform_texel_buffer_array_non_uniform_indexing;
features12.shader_storage_texel_buffer_array_non_uniform_indexing =
features_edi.shader_storage_texel_buffer_array_non_uniform_indexing;
features12.descriptor_binding_uniform_buffer_update_after_bind =
features_edi.descriptor_binding_uniform_buffer_update_after_bind;
features12.descriptor_binding_sampled_image_update_after_bind =
features_edi.descriptor_binding_sampled_image_update_after_bind;
features12.descriptor_binding_storage_image_update_after_bind =
features_edi.descriptor_binding_storage_image_update_after_bind;
features12.descriptor_binding_storage_buffer_update_after_bind =
features_edi.descriptor_binding_storage_buffer_update_after_bind;
features12.descriptor_binding_uniform_texel_buffer_update_after_bind =
features_edi.descriptor_binding_uniform_texel_buffer_update_after_bind;
features12.descriptor_binding_storage_texel_buffer_update_after_bind =
features_edi.descriptor_binding_storage_texel_buffer_update_after_bind;
features12.descriptor_binding_update_unused_while_pending =
features_edi.descriptor_binding_update_unused_while_pending;
features12.descriptor_binding_partially_bound =
features_edi.descriptor_binding_partially_bound;
features12.descriptor_binding_variable_descriptor_count =
features_edi.descriptor_binding_variable_descriptor_count;
features12.runtime_descriptor_array = features_edi.runtime_descriptor_array;
}
if !graphics.instance.enabled().vk1_2 && has_extension(KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)
{
features12.buffer_device_address = features_bda.buffer_device_address;
features12.buffer_device_address_capture_replay =
features_bda.buffer_device_address_capture_replay;
features12.buffer_device_address_multi_device =
features_bda.buffer_device_address_multi_device;
}
if !graphics.instance.enabled().vk1_3 && has_extension(KHR_DYNAMIC_RENDERING_EXTENSION_NAME) {
features13.dynamic_rendering = features_dr.dynamic_rendering;
}
let mut properties = Properties {
extension: extension_properties,
family: family_properties,
memory: memory_properties,
v10: properties10,
v11: properties11.build_dangling(),
v12: properties12.build_dangling(),
v13: properties13.build_dangling(),
acc: properties_acc.build_dangling(),
rt: properties_rt.build_dangling(),
};
let mut features = Features {
v10: features10,
v11: features11.build_dangling(),
v12: features12.build_dangling(),
v13: features13.build_dangling(),
acc: features_acc.build_dangling(),
rt: features_rt.build_dangling(),
};
properties.v11.p_next = std::ptr::null_mut();
properties.v12.p_next = std::ptr::null_mut();
properties.v13.p_next = std::ptr::null_mut();
properties.acc.p_next = std::ptr::null_mut();
properties.rt.p_next = std::ptr::null_mut();
features.v11.p_next = std::ptr::null_mut();
features.v12.p_next = std::ptr::null_mut();
features.v13.p_next = std::ptr::null_mut();
features.acc.p_next = std::ptr::null_mut();
features.rt.p_next = std::ptr::null_mut();
(properties, features)
}
impl Properties {
pub(crate) fn has_extension(&self, name: &CStr) -> bool {
self.extension
.iter()
.any(|p| unsafe { CStr::from_ptr(&p.extension_name[0]) } == name)
}
}
#[derive(Debug)]
pub struct PhysicalDevice {
physical: vk1_0::PhysicalDevice,
properties: Properties,
features: Features,
}
impl PhysicalDevice {
pub(crate) unsafe fn new(physical: vk1_0::PhysicalDevice) -> Self {
let (properties, features) = collect_properties_and_features(physical);
info!("{:#?}", properties);
PhysicalDevice {
properties,
features,
physical,
}
}
pub(crate) fn graphics(&self) -> &'static Graphics {
unsafe {
Graphics::get_unchecked()
}
}
pub fn info(&self) -> DeviceInfo {
let mut features = Vec::new();
if self.features.v12.scalar_block_layout > 0 {
features.push(Feature::ScalarBlockLayout);
}
if self.features.v12.runtime_descriptor_array > 0 {
features.push(Feature::RuntimeDescriptorArray);
}
if self
.features
.v12
.descriptor_binding_uniform_buffer_update_after_bind
> 0
{
features.push(Feature::DescriptorBindingUniformBufferUpdateAfterBind);
}
if self
.features
.v12
.descriptor_binding_sampled_image_update_after_bind
> 0
{
features.push(Feature::DescriptorBindingSampledImageUpdateAfterBind);
}
if self
.features
.v12
.descriptor_binding_storage_image_update_after_bind
> 0
{
features.push(Feature::DescriptorBindingStorageImageUpdateAfterBind);
}
if self
.features
.v12
.descriptor_binding_storage_buffer_update_after_bind
> 0
{
features.push(Feature::DescriptorBindingStorageBufferUpdateAfterBind);
}
if self
.features
.v12
.descriptor_binding_uniform_texel_buffer_update_after_bind
> 0
{
features.push(Feature::DescriptorBindingUniformTexelBufferUpdateAfterBind);
}
if self
.features
.v12
.descriptor_binding_storage_texel_buffer_update_after_bind
> 0
{
features.push(Feature::DescriptorBindingStorageTexelBufferUpdateAfterBind);
}
if self
.features
.v12
.descriptor_binding_update_unused_while_pending
> 0
{
features.push(Feature::DescriptorBindingUpdateUnusedWhilePending);
}
if self.features.v12.descriptor_binding_partially_bound > 0 {
features.push(Feature::DescriptorBindingPartiallyBound);
}
if self.features.v12.buffer_device_address > 0 {
features.push(Feature::BufferDeviceAddress);
}
if self.features.v13.dynamic_rendering != 0 {
features.push(Feature::DynamicRendering);
}
if self.features.acc.acceleration_structure != 0 {
assert!(features.contains(&Feature::BufferDeviceAddress));
features.push(Feature::AccelerationStructure);
}
if self.features.rt.ray_tracing_pipeline != 0 {
assert!(features.contains(&Feature::AccelerationStructure));
features.push(Feature::RayTracingPipeline);
}
if self.graphics().instance.enabled().khr_surface
&& self
.properties
.has_extension(unsafe { CStr::from_ptr(KHR_SWAPCHAIN_EXTENSION_NAME) })
{
features.push(Feature::SurfacePresentation);
if self
.properties
.has_extension(unsafe { CStr::from_ptr(GOOGLE_DISPLAY_TIMING_EXTENSION_NAME) })
{
features.push(Feature::DisplayTiming);
}
}
DeviceInfo {
kind: match self.properties.v10.device_type {
vk1_0::PhysicalDeviceType::INTEGRATED_GPU => Some(DeviceKind::Integrated),
vk1_0::PhysicalDeviceType::DISCRETE_GPU => Some(DeviceKind::Discrete),
vk1_0::PhysicalDeviceType::CPU => Some(DeviceKind::Software),
vk1_0::PhysicalDeviceType::OTHER | vk1_0::PhysicalDeviceType::VIRTUAL_GPU => None,
_ => {
error!(
"Unexpected device type value: {:?}",
self.properties.v10.device_type
);
None
}
},
name: unsafe {
assert!(
self.properties.v10.device_name.contains(&0),
"Valid C string expected"
);
CStr::from_ptr(&self.properties.v10.device_name[0])
}
.to_string_lossy()
.into_owned(),
features,
families: self
.properties
.family
.iter()
.map(|f| FamilyInfo {
count: f
.queue_count
.try_into()
.expect("More families than memory size"),
capabilities: from_erupt(f.queue_flags),
})
.collect(),
}
}
#[cfg_attr(feature = "tracing", tracing::instrument(skip(self, queues)))]
pub fn create_device<Q>(
self,
features: &[Feature],
queues: Q,
) -> Result<(Device, Q::Queues), CreateDeviceError<Q::Error>>
where
Q: QueuesQuery,
{
let (query, collector) = queues
.query(&self.info().families)
.map_err(|source| CreateDeviceError::CannotFindRequeredQueues { source })?;
let families = query.as_ref();
trace!("Creating device");
let mut device_create_info = vk1_0::DeviceCreateInfoBuilder::new();
let mut requested_features = RequestedFeatures::new(features);
let mut families_requested = HashMap::new();
for &(family, count) in families {
if self.properties.family.len() <= family {
return Err(CreateDeviceError::BadFamiliesRequested);
}
let priorities = families_requested.entry(family).or_insert_with(Vec::new);
if arith_gt(
priorities.len() + count,
self.properties.family[family].queue_count,
) {
return Err(CreateDeviceError::BadFamiliesRequested);
}
priorities.resize(priorities.len() + count, 1.0f32);
}
let device_queue_create_infos = families_requested
.iter()
.map(|(&index, priorities)| {
vk1_0::DeviceQueueCreateInfoBuilder::new()
.queue_family_index(
index
.try_into()
.expect("More families than bytes in memory space"),
)
.queue_priorities(priorities)
})
.collect::<Vec<_>>();
device_create_info = device_create_info.queue_create_infos(&device_queue_create_infos);
let mut features2 = vk1_1::PhysicalDeviceFeatures2Builder::new();
let mut features11 = vk1_2::PhysicalDeviceVulkan11FeaturesBuilder::new();
let mut features12 = vk1_2::PhysicalDeviceVulkan12FeaturesBuilder::new();
let mut features13 = vk1_3::PhysicalDeviceVulkan13FeaturesBuilder::new();
let mut features_sbl = vk1_2::PhysicalDeviceScalarBlockLayoutFeaturesBuilder::new();
let mut features_edi = vk1_2::PhysicalDeviceDescriptorIndexingFeaturesBuilder::new();
let mut features_bda = vk1_2::PhysicalDeviceBufferDeviceAddressFeaturesBuilder::new();
let mut features_acc = acc::PhysicalDeviceAccelerationStructureFeaturesKHRBuilder::new();
let mut features_rt = rt::PhysicalDeviceRayTracingPipelineFeaturesKHRBuilder::new();
let mut features_dr = vk1_3::PhysicalDeviceDynamicRenderingFeaturesBuilder::new();
let include_features11 = false;
let mut include_features12 = false;
let mut include_features13 = false;
let mut include_features_sbl = false;
let mut include_features_edi = false;
let mut include_features_bda = false;
let mut include_features_acc = false;
let mut include_features_rt = false;
let mut include_features_dr = false;
let mut enable_exts = SmallVec::<[_; 10]>::new();
let mut push_ext = |name| {
let name = unsafe { CStr::from_ptr(name) };
assert!(
self.properties.has_extension(name),
"Extension {:?} is missing",
name
);
if !enable_exts.contains(&name.as_ptr()) {
enable_exts.push(name.as_ptr());
}
};
if requested_features.take(Feature::SurfacePresentation) {
push_ext(KHR_SWAPCHAIN_EXTENSION_NAME);
}
if requested_features.take(Feature::ScalarBlockLayout) {
if self.features.v12.scalar_block_layout > 0 {
features12.scalar_block_layout = 1;
features_sbl.scalar_block_layout = 1;
include_features12 = true;
include_features_sbl = true;
} else {
panic!("Attempt to enable unsupported feature `ScalarBlockLayout`");
}
}
if requested_features.take(Feature::BufferDeviceAddress) {
if self.features.v12.buffer_device_address > 0 {
features12.buffer_device_address = 1;
features_bda.buffer_device_address = 1;
include_features12 = true;
include_features_bda = true;
} else {
panic!("Attempt to enable unsupported feature `BufferDeviceAddress`");
}
}
if requested_features.take(Feature::AccelerationStructure) {
assert_ne!(
self.features.acc.acceleration_structure, 0,
"Attempt to enable unsupported feature `AccelerationStructure`"
);
assert_ne!(
features12.buffer_device_address, 0,
"`BufferDeviceAddress` feature must be enabled when `AccelerationStructure` feature is enabled"
);
features_acc.acceleration_structure = 1;
include_features_acc = true;
}
if requested_features.take(Feature::RayTracingPipeline) {
assert_ne!(
self.features.rt.ray_tracing_pipeline, 0,
"Attempt to enable unsupported feature `RayTracing`"
);
assert_ne!(
features_acc.acceleration_structure, 0,
"`AccelerationStructure` feature must be enabled when `RayTracingPipeline` feature is enabled"
);
features_rt.ray_tracing_pipeline = 1;
include_features_rt = true;
}
if requested_features.take(Feature::RuntimeDescriptorArray) {
if self.features.v12.runtime_descriptor_array != 0 {
features12.runtime_descriptor_array = 1;
features_edi.runtime_descriptor_array = 1;
include_features12 = true;
include_features_edi = true;
} else {
panic!("Attempt to enable unsupported feature `RuntimeDescriptorArray`");
}
}
if requested_features.take(Feature::DescriptorBindingUniformBufferUpdateAfterBind) {
if self
.features
.v12
.descriptor_binding_uniform_buffer_update_after_bind
> 0
{
features12.descriptor_binding_uniform_buffer_update_after_bind = 1;
include_features12 = true;
include_features_edi = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingUniformBufferUpdateAfterBind`")
}
}
if requested_features.take(Feature::DescriptorBindingSampledImageUpdateAfterBind) {
if self
.features
.v12
.descriptor_binding_sampled_image_update_after_bind
> 0
{
features12.descriptor_binding_sampled_image_update_after_bind = 1;
features_edi.descriptor_binding_sampled_image_update_after_bind = 1;
include_features12 = true;
include_features_edi = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingSampledImageUpdateAfterBind`")
}
}
if requested_features.take(Feature::DescriptorBindingStorageImageUpdateAfterBind) {
if self
.features
.v12
.descriptor_binding_storage_image_update_after_bind
> 0
{
features12.descriptor_binding_storage_image_update_after_bind = 1;
features_edi.descriptor_binding_storage_image_update_after_bind = 1;
include_features12 = true;
include_features_edi = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingStorageImageUpdateAfterBind`")
}
}
if requested_features.take(Feature::DescriptorBindingStorageBufferUpdateAfterBind) {
if self
.features
.v12
.descriptor_binding_storage_buffer_update_after_bind
> 0
{
features12.descriptor_binding_storage_buffer_update_after_bind = 1;
features_edi.descriptor_binding_storage_buffer_update_after_bind = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingStorageBufferUpdateAfterBind`")
}
}
if requested_features.take(Feature::DescriptorBindingUniformTexelBufferUpdateAfterBind) {
if self
.features
.v12
.descriptor_binding_uniform_texel_buffer_update_after_bind
> 0
{
features12.descriptor_binding_uniform_texel_buffer_update_after_bind = 1;
features_edi.descriptor_binding_uniform_texel_buffer_update_after_bind = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingUniformTexelBufferUpdateAfterBind`")
}
}
if requested_features.take(Feature::DescriptorBindingStorageTexelBufferUpdateAfterBind) {
if self
.features
.v12
.descriptor_binding_storage_texel_buffer_update_after_bind
> 0
{
features12.descriptor_binding_storage_texel_buffer_update_after_bind = 1;
features_edi.descriptor_binding_storage_texel_buffer_update_after_bind = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingStorageTexelBufferUpdateAfterBind`")
}
}
if requested_features.take(Feature::DescriptorBindingUpdateUnusedWhilePending) {
if self
.features
.v12
.descriptor_binding_update_unused_while_pending
> 0
{
features12.descriptor_binding_update_unused_while_pending = 1;
features_edi.descriptor_binding_update_unused_while_pending = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingUpdateUnusedWhilePending`")
}
}
if requested_features.take(Feature::DescriptorBindingPartiallyBound) {
if self.features.v12.descriptor_binding_partially_bound > 0 {
features12.descriptor_binding_partially_bound = 1;
features_edi.descriptor_binding_partially_bound = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!("Attempt to enable unsupported feature `DescriptorBindingPartiallyBound`")
}
}
if requested_features.take(Feature::ShaderSampledImageNonUniformIndexing) {
assert!(requested_features.check(Feature::ShaderSampledImageDynamicIndexing));
if self
.features
.v12
.shader_sampled_image_array_non_uniform_indexing
> 0
{
features12.shader_sampled_image_array_non_uniform_indexing = 1;
features_edi.shader_sampled_image_array_non_uniform_indexing = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!(
"Attempt to enable unsupported feature `ShaderSampledImageNonUniformIndexing`"
)
}
}
if requested_features.take(Feature::ShaderSampledImageDynamicIndexing) {
assert_ne!(
self.features
.v10
.shader_sampled_image_array_dynamic_indexing,
0,
"Attempt to enable unsupported feature `ShaderSampledImageDynamicIndexing`"
);
features2
.features
.shader_sampled_image_array_dynamic_indexing = 1;
}
if requested_features.take(Feature::ShaderStorageImageNonUniformIndexing) {
assert!(requested_features.check(Feature::ShaderStorageImageDynamicIndexing));
if self
.features
.v12
.shader_storage_image_array_non_uniform_indexing
> 0
{
features12.shader_storage_image_array_non_uniform_indexing = 1;
features_edi.shader_storage_image_array_non_uniform_indexing = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!(
"Attempt to enable unsupported feature `ShaderStorageImageNonUniformIndexing`"
)
}
}
if requested_features.take(Feature::ShaderStorageImageDynamicIndexing) {
assert_ne!(
self.features
.v10
.shader_storage_image_array_dynamic_indexing,
0,
"Attempt to enable unsupported feature `ShaderStorageImageDynamicIndexing`"
);
features2
.features
.shader_storage_image_array_dynamic_indexing = 1;
}
if requested_features.take(Feature::ShaderUniformBufferNonUniformIndexing) {
assert!(requested_features.check(Feature::ShaderUniformBufferDynamicIndexing));
if self
.features
.v12
.shader_uniform_buffer_array_non_uniform_indexing
> 0
{
features12.shader_uniform_buffer_array_non_uniform_indexing = 1;
features_edi.shader_uniform_buffer_array_non_uniform_indexing = 1;
include_features_edi = true;
include_features12 = true;
} else {
panic!(
"Attempt to enable unsupported feature `ShaderUniformBufferNonUniformIndexing`"
)
}
}
if requested_features.take(Feature::ShaderUniformBufferDynamicIndexing) {
assert_ne!(
self.features
.v10
.shader_uniform_buffer_array_dynamic_indexing,
0,
"Attempt to enable unsupported feature `ShaderUniformBufferDynamicIndexing`"
);
features2
.features
.shader_uniform_buffer_array_dynamic_indexing = 1;
}
if requested_features.take(Feature::ShaderStorageBufferNonUniformIndexing) {
assert!(requested_features.check(Feature::ShaderStorageBufferDynamicIndexing));
if self
.features
.v12
.shader_storage_buffer_array_non_uniform_indexing
> 0
{
features12.shader_storage_buffer_array_non_uniform_indexing = 1;
features_edi.shader_storage_buffer_array_non_uniform_indexing = 1;
include_features12 = true;
include_features_edi = true;
} else {
panic!(
"Attempt to enable unsupported feature `ShaderStorageBufferNonUniformIndexing`"
)
}
}
if requested_features.take(Feature::ShaderStorageBufferDynamicIndexing) {
assert_ne!(
self.features
.v10
.shader_storage_buffer_array_dynamic_indexing,
0,
"Attempt to enable unsupported feature `ShaderStorageBufferDynamicIndexing`"
);
features2
.features
.shader_storage_buffer_array_dynamic_indexing = 1;
}
if requested_features.take(Feature::DisplayTiming) {
push_ext(GOOGLE_DISPLAY_TIMING_EXTENSION_NAME);
}
if requested_features.take(Feature::DynamicRendering) {
assert_ne!(
self.features.v13.dynamic_rendering, 0,
"Attempt to enable unsupported feature `DynamicRendering`"
);
features13.dynamic_rendering = 1;
features_dr.dynamic_rendering = 1;
include_features13 = true;
include_features_dr = true;
}
device_create_info = device_create_info.enabled_features(&features2.features);
if self.graphics().instance.enabled().vk1_1 {
} else {
assert!(!include_features11);
assert!(!include_features_rt);
}
if self.graphics().instance.enabled().vk1_2 {
include_features_sbl = false;
include_features_edi = false;
include_features_bda = false;
} else {
include_features12 = false;
}
if self.graphics().instance.enabled().vk1_3 {
include_features_dr = false;
} else {
include_features13 = false;
}
if include_features_sbl {
push_ext(EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
device_create_info = device_create_info.extend_from(&mut features_sbl);
}
if include_features_edi {
push_ext(EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
device_create_info = device_create_info.extend_from(&mut features_edi);
}
if include_features_bda {
push_ext(KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
device_create_info = device_create_info.extend_from(&mut features_bda);
}
if include_features_acc {
push_ext(KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
push_ext(KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
device_create_info = device_create_info.extend_from(&mut features_acc);
}
if include_features_rt {
push_ext(KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
device_create_info = device_create_info.extend_from(&mut features_rt);
}
if include_features_dr {
push_ext(KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
device_create_info = device_create_info.extend_from(&mut features_dr);
}
if include_features13 {
device_create_info = device_create_info.extend_from(&mut features13);
}
if include_features12 {
device_create_info = device_create_info.extend_from(&mut features12);
}
if include_features11 {
device_create_info = device_create_info.extend_from(&mut features11);
}
device_create_info = device_create_info.enabled_extension_names(&enable_exts);
requested_features.assert_empty();
let instance = &self.graphics().instance;
let result = unsafe { DeviceLoader::new(instance, self.physical, &device_create_info) };
let logical = match result {
Err(LoaderError::SymbolNotAvailable) => {
return Err(CreateDeviceError::FunctionLoadFailed);
}
Err(LoaderError::VulkanError(vk1_0::Result::ERROR_OUT_OF_HOST_MEMORY)) => {
out_of_host_memory()
}
Err(LoaderError::VulkanError(vk1_0::Result::ERROR_OUT_OF_DEVICE_MEMORY)) => {
return Err(OutOfMemory.into())
}
Err(LoaderError::VulkanError(err)) => unexpected_result(err),
Ok(ok) => ok,
};
let family_properties = self.properties.family.clone();
let version = self.graphics().version;
let device = Device::new(
logical,
self.physical,
self.properties,
Features {
v10: features2.features,
v11: features11.build_dangling(),
v12: features12.build_dangling(),
v13: features13.build_dangling(),
acc: features_acc.build_dangling(),
rt: features_rt.build_dangling(),
},
version,
families.iter().flat_map(|&(family, count)| {
(0..count).map(move |index| {
let index = index.try_into().unwrap();
let family = family.try_into().unwrap();
QueueId { family, index }
})
}),
);
let families = families
.iter()
.map(|&(family, count)| {
let capabilities = from_erupt(family_properties[family].queue_flags);
Family {
capabilities,
queues: (0..count)
.map(|index| {
let index = index.try_into().unwrap();
let family = family.try_into().unwrap();
let queue = unsafe { device.logical().get_device_queue(index, family) };
Queue::new(
queue,
vk1_0::CommandPool::null(),
device.clone(),
QueueId { family, index },
capabilities,
)
})
.collect(),
}
})
.collect();
debug!("Device created");
Ok((device, Q::collect(collector, families)))
}
}
struct RequestedFeatures {
array: Vec<Feature>,
}
impl RequestedFeatures {
fn new(features: &[Feature]) -> Self {
RequestedFeatures {
array: features.to_vec(),
}
}
fn take(&mut self, feature: Feature) -> bool {
if let Some(index) = self.array.iter().position(|&f| f == feature) {
self.array.swap_remove(index);
true
} else {
false
}
}
fn check(&self, feature: Feature) -> bool {
self.array.contains(&feature)
}
fn assert_empty(self) {
assert!(
self.array.is_empty(),
"Features: {:#?} are unsupported",
&self.array
);
}
}
#[allow(dead_code)]
fn check() {
assert_object::<PhysicalDevice>();
}