idk? pdev, queue refactor

This commit is contained in:
janis 2026-03-28 18:11:10 +01:00
parent 20f743d74b
commit 05bf7dd61f
6 changed files with 836 additions and 283 deletions

View file

@ -16,8 +16,7 @@ use tinyvec::{ArrayVec, array_vec};
use crate::{ use crate::{
Error, ExtendsDeviceProperties2Debug, Instance, PhysicalDevice, PhysicalDeviceFeatures, Error, ExtendsDeviceProperties2Debug, Instance, PhysicalDevice, PhysicalDeviceFeatures,
PhysicalDeviceProperties, Queue, Result, VkNameList, instance::InstanceInner, PhysicalDeviceInfo, PhysicalDeviceProperties, Queue, Result, instance::InstanceInner, sync,
make_extention_properties, sync,
}; };
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -127,6 +126,7 @@ pub struct DeviceInner {
present_queue: Queue, present_queue: Queue,
sync_threadpool: sync::SyncThreadpool, sync_threadpool: sync::SyncThreadpool,
features: crate::PhysicalDeviceFeatures, features: crate::PhysicalDeviceFeatures,
properties: crate::PhysicalDeviceProperties,
} }
impl core::fmt::Debug for DeviceInner { impl core::fmt::Debug for DeviceInner {
@ -175,7 +175,6 @@ pub struct DeviceDesc<'a> {
pub layer_settings: &'a [vk::LayerSettingEXT<'a>], pub layer_settings: &'a [vk::LayerSettingEXT<'a>],
pub instance_extensions: &'a [Extension<'a>], pub instance_extensions: &'a [Extension<'a>],
pub display_handle: Option<RawDisplayHandle>, pub display_handle: Option<RawDisplayHandle>,
pub features: crate::PhysicalDeviceFeatures,
} }
const VALIDATION_LAYER_NAME: &core::ffi::CStr = c"VK_LAYER_KHRONOS_validation"; const VALIDATION_LAYER_NAME: &core::ffi::CStr = c"VK_LAYER_KHRONOS_validation";
@ -221,7 +220,6 @@ impl<'a> Default for DeviceDesc<'a> {
layer_settings: &[], layer_settings: &[],
instance_extensions: Default::default(), instance_extensions: Default::default(),
display_handle: Default::default(), display_handle: Default::default(),
features: Default::default(),
} }
} }
} }
@ -695,58 +693,6 @@ pub struct Device(Arc<DeviceInner>);
pub type WeakDevice = std::sync::Weak<DeviceInner>; pub type WeakDevice = std::sync::Weak<DeviceInner>;
impl Device { impl Device {
pub fn new_from_default_desc(
display_handle: Option<RawDisplayHandle>,
with_instance_extensions: &[Extension<'_>],
) -> crate::Result<Self> {
Self::new_from_desc(DeviceDesc {
app_name: Some("Vidya"),
app_version: vk::make_api_version(0, 0, 1, 0),
display_handle,
features: crate::PhysicalDeviceFeatures::default()
.version(vk::make_api_version(0, 1, 3, 0))
.features10(
vk::PhysicalDeviceFeatures::default()
.sampler_anisotropy(true)
.fill_mode_non_solid(true)
.multi_draw_indirect(true),
)
.features11(
vk::PhysicalDeviceVulkan11Features::default().shader_draw_parameters(true),
)
.features12(
vk::PhysicalDeviceVulkan12Features::default()
.shader_int8(true)
.runtime_descriptor_array(true)
.descriptor_binding_partially_bound(true)
.shader_sampled_image_array_non_uniform_indexing(true)
.descriptor_binding_sampled_image_update_after_bind(true)
.storage_buffer8_bit_access(true),
)
.with_extension(
make_extention_properties(
ash::ext::mesh_shader::NAME,
ash::ext::mesh_shader::SPEC_VERSION,
),
vk::PhysicalDeviceMeshShaderFeaturesEXT::default()
.mesh_shader(true)
.task_shader(true),
)
.with_extension(
make_extention_properties(
ash::ext::index_type_uint8::NAME,
ash::ext::index_type_uint8::SPEC_VERSION,
),
vk::PhysicalDeviceIndexTypeUint8FeaturesEXT::default().index_type_uint8(true),
)
.with_extensions2([make_extention_properties(
khr::spirv_1_4::NAME,
khr::spirv_1_4::SPEC_VERSION,
)]),
instance_extensions: with_instance_extensions,
..Default::default()
})
}
pub fn new_from_desc(desc: DeviceDesc) -> crate::Result<Self> { pub fn new_from_desc(desc: DeviceDesc) -> crate::Result<Self> {
let instance = Instance::new(&crate::instance::InstanceDesc { let instance = Instance::new(&crate::instance::InstanceDesc {
app_name: desc.app_name, app_name: desc.app_name,
@ -761,28 +707,29 @@ impl Device {
display_handle: desc.display_handle, display_handle: desc.display_handle,
})?; })?;
let mut features = desc.features.with_extension2(make_extention_properties( // //these are required for the renderpass
khr::swapchain::NAME, // let features13 = features.physical_features_13.get_or_insert_default();
khr::swapchain::SPEC_VERSION, // features13.synchronization2 = vk::TRUE;
)); // features13.dynamic_rendering = vk::TRUE;
// features13.maintenance4 = vk::TRUE;
//these are required for the renderpass let features = PhysicalDeviceFeatures {
let features13 = features.physical_features_13.get_or_insert_default(); core13: vk::PhysicalDeviceVulkan13Features {
features13.synchronization2 = vk::TRUE; synchronization2: vk::TRUE,
features13.dynamic_rendering = vk::TRUE; dynamic_rendering: vk::TRUE,
features13.maintenance4 = vk::TRUE; maintenance4: vk::TRUE,
..Default::default()
},
..Default::default()
};
// Consider this: switching physical device in game? // Consider this: switching physical device in game?
// anything above this point is device agnostic, everything below would have to be recreated // anything above this point is device agnostic, everything below would have to be recreated
// additionally, pdev would have to be derived from a device and not a scoring function. // additionally, pdev would have to be derived from a device and not a scoring function.
let pdev = DeviceBuilder::choose_physical_device( let pdev = instance.choose_adapter_default(
&instance.inner, None,
desc.display_handle, &[make_extension!(ext::mesh_shader)],
&features, Some(&features),
vec![Box::new(
vk::PhysicalDeviceMeshShaderPropertiesEXT::default(),
)],
)?; )?;
tracing::trace!("pdev: {pdev:?}"); tracing::trace!("pdev: {pdev:?}");
@ -793,7 +740,7 @@ impl Device {
pub fn new( pub fn new(
instance: Arc<InstanceInner>, instance: Arc<InstanceInner>,
physical: PhysicalDevice, physical: PhysicalDeviceInfo,
mut features: crate::PhysicalDeviceFeatures, mut features: crate::PhysicalDeviceFeatures,
) -> VkResult<Self> { ) -> VkResult<Self> {
// we have 4 queues at most: graphics, compute, transfer, present // we have 4 queues at most: graphics, compute, transfer, present
@ -912,6 +859,9 @@ impl Device {
pub fn features(&self) -> &crate::PhysicalDeviceFeatures { pub fn features(&self) -> &crate::PhysicalDeviceFeatures {
&self.0.features &self.0.features
} }
pub fn properties(&self) -> &crate::PhysicalDeviceProperties {
&self.0.properties
}
pub fn physical_device(&self) -> &PhysicalDevice { pub fn physical_device(&self) -> &PhysicalDevice {
&self.0.physical &self.0.physical
} }

View file

@ -1,14 +1,17 @@
use std::{ use std::{
cmp::Ordering,
ffi::{CStr, CString}, ffi::{CStr, CString},
sync::Arc, sync::Arc,
}; };
use ash::{Entry, ext, vk}; use ash::{Entry, ext, khr, vk};
use raw_window_handle::RawDisplayHandle; use raw_window_handle::RawDisplayHandle;
use crate::{ use crate::{
Error, PhysicalDeviceFeatures, PhysicalDeviceInfo,
device::{Extension, get_extensions, get_layers}, device::{Extension, get_extensions, get_layers},
make_extension, get_physical_device_features, get_physical_device_properties, make_extension,
swapchain::Surface,
}; };
pub struct DebugUtilsCreateInfo { pub struct DebugUtilsCreateInfo {
@ -155,6 +158,207 @@ impl Instance {
Ok(Self { inner: instance }) Ok(Self { inner: instance })
} }
fn choose_adapter(
&self,
surface: Option<&Surface>,
mut discriminator: impl FnMut(&PhysicalDeviceInfo, &PhysicalDeviceInfo) -> Ordering,
) -> crate::Result<PhysicalDeviceInfo> {
let pdevs = unsafe { self.inner.raw.enumerate_physical_devices()? };
let mut pdevs = pdevs
.into_iter()
.map(|pdev| -> crate::Result<PhysicalDeviceInfo> {
let properties = get_physical_device_properties(&self.inner, pdev)?;
let features = get_physical_device_features(&self.inner, pdev, &properties)?;
let surface_capabilities = if let Some(surface) = surface {
let capabilities = unsafe {
surface
.functor
.get_physical_device_surface_capabilities(pdev, surface.raw)?
};
let formats = unsafe {
surface
.functor
.get_physical_device_surface_formats(pdev, surface.raw)?
};
Some((capabilities, formats))
} else {
None
};
Ok(PhysicalDeviceInfo {
pdev,
properties,
features,
surface_capabilities,
})
})
.filter_map(Result::ok)
.collect::<Vec<_>>();
pdevs.sort_unstable_by(&mut discriminator);
pdevs.pop().ok_or(Error::NoAdapter)
}
pub(crate) fn choose_adapter_default(
&self,
surface: Option<&Surface>,
required_extensions: &[Extension],
required_features: Option<&PhysicalDeviceFeatures>,
) -> crate::Result<PhysicalDeviceInfo> {
self.choose_adapter(surface, |a, b| {
// Extensions: we definitely need swapchain.
match a
.properties
.supports_extension(make_extension!(khr::swapchain))
.cmp(
&b.properties
.supports_extension(make_extension!(khr::swapchain)),
) {
Ordering::Equal => {}
other => return other,
}
for ext in required_extensions {
match a.properties.supports_extension(*ext) {
true => {}
false => return Ordering::Less,
}
}
// Check surface compatibility
// TODO
if let Some(ref required_features) = required_features {
if b.features.superset_of(&required_features)
&& !a.features.superset_of(&required_features)
{
return Ordering::Less;
}
}
// check specific features that we need
match a
.features
.core13
.synchronization2
.cmp(&b.features.core13.synchronization2)
{
Ordering::Equal => {}
other => return other,
}
match a
.features
.core13
.dynamic_rendering
.cmp(&b.features.core13.dynamic_rendering)
{
Ordering::Equal => {}
other => return other,
}
match a
.features
.core13
.maintenance4
.cmp(&b.features.core13.maintenance4)
{
Ordering::Equal => {}
other => return other,
}
// Prefer discrete GPUs
let a_discrete = a.properties.core.device_type == vk::PhysicalDeviceType::DISCRETE_GPU;
let b_discrete = b.properties.core.device_type == vk::PhysicalDeviceType::DISCRETE_GPU;
match (a_discrete, b_discrete) {
(true, false) => return Ordering::Greater,
(false, true) => return Ordering::Less,
_ => {}
}
// Then prefer newer APIs
match a
.properties
.core
.api_version
.cmp(&b.properties.core.api_version)
{
Ordering::Equal => {}
other => return other,
}
// Prefer larger memory
match a
.properties
.get_device_local_memory_count()
.cmp(&b.properties.get_device_local_memory_count())
{
Ordering::Equal => {}
other => return other,
}
// Prefer larger texture size
match a
.properties
.core
.limits
.max_image_dimension2_d
.cmp(&b.properties.core.limits.max_image_dimension2_d)
{
Ordering::Equal => {}
other => return other,
}
Ordering::Equal
})
}
/// So... basically this probably doesn't matter because the graphics queue will always be a present queue as well...
pub(crate) fn query_presentation_support(
&self,
pdev: vk::PhysicalDevice,
queue_family: u32,
display_handle: RawDisplayHandle,
) -> bool {
unsafe {
match display_handle {
RawDisplayHandle::Xlib(display) => {
let surface =
ash::khr::xlib_surface::Instance::new(&self.inner.entry, &self.inner.raw);
surface.get_physical_device_xlib_presentation_support(
pdev,
queue_family,
display.display.unwrap().as_ptr() as _,
display.screen as _,
)
}
RawDisplayHandle::Xcb(_xcb_display_handle) => todo!("xcb"),
RawDisplayHandle::Wayland(wayland_display_handle) => {
let surface = ash::khr::wayland_surface::Instance::new(
&self.inner.entry,
&self.inner.raw,
);
surface.get_physical_device_wayland_presentation_support(
pdev,
queue_family,
wayland_display_handle.display.cast().as_mut(),
)
}
RawDisplayHandle::Drm(_) => {
// idk ?
true
}
RawDisplayHandle::Windows(_) => {
ash::khr::win32_surface::Instance::new(&self.inner.entry, &self.inner.raw)
.get_physical_device_win32_presentation_support(pdev, queue_family)
}
_ => panic!("unsupported platform"),
}
}
}
} }
pub(crate) struct DebugUtils { pub(crate) struct DebugUtils {

View file

@ -8,14 +8,15 @@
use std::{collections::HashMap, ffi::CStr, fmt::Debug, marker::PhantomData, sync::Arc}; use std::{collections::HashMap, ffi::CStr, fmt::Debug, marker::PhantomData, sync::Arc};
use bitflags::bitflags;
use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use parking_lot::{Mutex, MutexGuard}; use parking_lot::{Mutex, MutexGuard};
use ash::{ use ash::{
Entry, ext, Entry, ext, khr,
prelude::VkResult, prelude::VkResult,
vk::{self}, vk::{self, SurfaceCapabilitiesKHR},
}; };
use dyn_clone::DynClone; use dyn_clone::DynClone;
@ -84,6 +85,8 @@ use util::Rgba;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
#[error("No Physical Device found for this instance.")]
NoAdapter,
#[error("Swapchain suboptimal.")] #[error("Swapchain suboptimal.")]
SuboptimalSwapchain, SuboptimalSwapchain,
#[error(transparent)] #[error(transparent)]
@ -155,6 +158,9 @@ fn compatible_extension_properties(
} }
} }
mod queue;
// Queues must be externally synchronised for calls to `vkQueueSubmit` and `vkQueuePresentKHR`.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Queue(Arc<Mutex<vk::Queue>>, u32); pub struct Queue(Arc<Mutex<vk::Queue>>, u32);
@ -200,230 +206,434 @@ impl<T: vk::ExtendsPhysicalDeviceProperties2 + Debug + DynClone + Send + Sync>
{ {
} }
#[derive(Debug)]
pub struct PhysicalDeviceInfo {
pub pdev: vk::PhysicalDevice,
pub properties: PhysicalDeviceProperties,
pub features: PhysicalDeviceFeatures,
pub surface_capabilities: Option<(SurfaceCapabilitiesKHR, Vec<vk::SurfaceFormatKHR>)>,
}
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct PhysicalDeviceFeatures { pub struct PhysicalDeviceFeatures {
pub version: u32, pub core: vk::PhysicalDeviceFeatures,
pub physical_features_10: vk::PhysicalDeviceFeatures, pub core11: vk::PhysicalDeviceVulkan11Features<'static>,
pub physical_features_11: Option<vk::PhysicalDeviceVulkan11Features<'static>>, pub core12: vk::PhysicalDeviceVulkan12Features<'static>,
pub physical_features_12: Option<vk::PhysicalDeviceVulkan12Features<'static>>, pub core13: vk::PhysicalDeviceVulkan13Features<'static>,
pub physical_features_13: Option<vk::PhysicalDeviceVulkan13Features<'static>>, pub mesh_shader: Option<vk::PhysicalDeviceMeshShaderFeaturesEXT<'static>>,
pub extra_features: Vec<Box<dyn ExtendsDeviceFeatures2Debug>>,
pub device_extensions: Vec<vk::ExtensionProperties>,
} }
impl PhysicalDeviceFeatures { impl PhysicalDeviceFeatures {
fn version(self, version: u32) -> Self { pub fn superset_of(&self, other: &PhysicalDeviceFeatures) -> bool {
Self { version, ..self } fn core_superset_of(
} a: &vk::PhysicalDeviceFeatures,
fn all_default() -> Self { b: &vk::PhysicalDeviceFeatures,
Self::default() ) -> bool {
.features11(Default::default()) (b.robust_buffer_access == vk::FALSE
.features12(Default::default()) || a.robust_buffer_access != b.robust_buffer_access)
.features13(Default::default()) && (b.full_draw_index_uint32 == vk::FALSE
|| a.full_draw_index_uint32 != b.full_draw_index_uint32)
&& (b.image_cube_array == vk::FALSE || a.image_cube_array != b.image_cube_array)
&& (b.independent_blend == vk::FALSE || a.independent_blend != b.independent_blend)
&& (b.geometry_shader == vk::FALSE || a.geometry_shader != b.geometry_shader)
&& (b.tessellation_shader == vk::FALSE
|| a.tessellation_shader != b.tessellation_shader)
&& (b.sample_rate_shading == vk::FALSE
|| a.sample_rate_shading != b.sample_rate_shading)
&& (b.dual_src_blend == vk::FALSE || a.dual_src_blend != b.dual_src_blend)
&& (b.logic_op == vk::FALSE || a.logic_op != b.logic_op)
&& (b.multi_draw_indirect == vk::FALSE
|| a.multi_draw_indirect != b.multi_draw_indirect)
&& (b.draw_indirect_first_instance == vk::FALSE
|| a.draw_indirect_first_instance != b.draw_indirect_first_instance)
&& (b.depth_clamp == vk::FALSE || a.depth_clamp != b.depth_clamp)
&& (b.depth_bias_clamp == vk::FALSE || a.depth_bias_clamp != b.depth_bias_clamp)
&& (b.fill_mode_non_solid == vk::FALSE
|| a.fill_mode_non_solid != b.fill_mode_non_solid)
&& (b.depth_bounds == vk::FALSE || a.depth_bounds != b.depth_bounds)
&& (b.wide_lines == vk::FALSE || a.wide_lines != b.wide_lines)
&& (b.large_points == vk::FALSE || a.large_points != b.large_points)
&& (b.alpha_to_one == vk::FALSE || a.alpha_to_one != b.alpha_to_one)
&& (b.multi_viewport == vk::FALSE || a.multi_viewport != b.multi_viewport)
&& (b.sampler_anisotropy == vk::FALSE
|| a.sampler_anisotropy != b.sampler_anisotropy)
&& (b.texture_compression_etc2 == vk::FALSE
|| a.texture_compression_etc2 != b.texture_compression_etc2)
&& (b.texture_compression_astc_ldr == vk::FALSE
|| a.texture_compression_astc_ldr != b.texture_compression_astc_ldr)
&& (b.texture_compression_bc == vk::FALSE
|| a.texture_compression_bc != b.texture_compression_bc)
&& (b.occlusion_query_precise == vk::FALSE
|| a.occlusion_query_precise != b.occlusion_query_precise)
&& (b.pipeline_statistics_query == vk::FALSE
|| a.pipeline_statistics_query != b.pipeline_statistics_query)
&& (b.vertex_pipeline_stores_and_atomics == vk::FALSE
|| a.vertex_pipeline_stores_and_atomics != b.vertex_pipeline_stores_and_atomics)
&& (b.fragment_stores_and_atomics == vk::FALSE
|| a.fragment_stores_and_atomics != b.fragment_stores_and_atomics)
&& (b.shader_tessellation_and_geometry_point_size == vk::FALSE
|| a.shader_tessellation_and_geometry_point_size
!= b.shader_tessellation_and_geometry_point_size)
&& (b.shader_image_gather_extended == vk::FALSE
|| a.shader_image_gather_extended != b.shader_image_gather_extended)
&& (b.shader_storage_image_extended_formats == vk::FALSE
|| a.shader_storage_image_extended_formats
!= b.shader_storage_image_extended_formats)
&& (b.shader_storage_image_multisample == vk::FALSE
|| a.shader_storage_image_multisample != b.shader_storage_image_multisample)
&& (b.shader_storage_image_read_without_format == vk::FALSE
|| a.shader_storage_image_read_without_format
!= b.shader_storage_image_read_without_format)
&& (b.shader_storage_image_write_without_format == vk::FALSE
|| a.shader_storage_image_write_without_format
!= b.shader_storage_image_write_without_format)
&& (b.shader_uniform_buffer_array_dynamic_indexing == vk::FALSE
|| a.shader_uniform_buffer_array_dynamic_indexing
!= b.shader_uniform_buffer_array_dynamic_indexing)
&& (b.shader_sampled_image_array_dynamic_indexing == vk::FALSE
|| a.shader_sampled_image_array_dynamic_indexing
!= b.shader_sampled_image_array_dynamic_indexing)
&& (b.shader_storage_buffer_array_dynamic_indexing == vk::FALSE
|| a.shader_storage_buffer_array_dynamic_indexing
!= b.shader_storage_buffer_array_dynamic_indexing)
&& (b.shader_storage_image_array_dynamic_indexing == vk::FALSE
|| a.shader_storage_image_array_dynamic_indexing
!= b.shader_storage_image_array_dynamic_indexing)
&& (b.shader_clip_distance == vk::FALSE
|| a.shader_clip_distance != b.shader_clip_distance)
&& (b.shader_cull_distance == vk::FALSE
|| a.shader_cull_distance != b.shader_cull_distance)
&& (b.shader_float64 == vk::FALSE || a.shader_float64 != b.shader_float64)
&& (b.shader_int64 == vk::FALSE || a.shader_int64 != b.shader_int64)
&& (b.shader_int16 == vk::FALSE || a.shader_int16 != b.shader_int16)
&& (b.shader_resource_residency == vk::FALSE
|| a.shader_resource_residency != b.shader_resource_residency)
&& (b.shader_resource_min_lod == vk::FALSE
|| a.shader_resource_min_lod != b.shader_resource_min_lod)
&& (b.sparse_binding == vk::FALSE || a.sparse_binding != b.sparse_binding)
&& (b.sparse_residency_buffer == vk::FALSE
|| a.sparse_residency_buffer != b.sparse_residency_buffer)
&& (b.sparse_residency_image2_d == vk::FALSE
|| a.sparse_residency_image2_d != b.sparse_residency_image2_d)
&& (b.sparse_residency_image3_d == vk::FALSE
|| a.sparse_residency_image3_d != b.sparse_residency_image3_d)
&& (b.sparse_residency2_samples == vk::FALSE
|| a.sparse_residency2_samples != b.sparse_residency2_samples)
&& (b.sparse_residency4_samples == vk::FALSE
|| a.sparse_residency4_samples != b.sparse_residency4_samples)
&& (b.sparse_residency8_samples == vk::FALSE
|| a.sparse_residency8_samples != b.sparse_residency8_samples)
&& (b.sparse_residency16_samples == vk::FALSE
|| a.sparse_residency16_samples != b.sparse_residency16_samples)
&& (b.sparse_residency_aliased == vk::FALSE
|| a.sparse_residency_aliased != b.sparse_residency_aliased)
&& (b.variable_multisample_rate == vk::FALSE
|| a.variable_multisample_rate != b.variable_multisample_rate)
&& (b.inherited_queries == vk::FALSE || a.inherited_queries != b.inherited_queries)
} }
fn query(instance: &ash::Instance, pdev: vk::PhysicalDevice) -> Result<Self> { fn core11_superset_of(
let mut this = Self::all_default(); a: &vk::PhysicalDeviceVulkan11Features,
let mut features2 = this.features2(); b: &vk::PhysicalDeviceVulkan11Features,
let features = unsafe { ) -> bool {
instance.get_physical_device_features2(pdev, &mut features2); (b.storage_buffer16_bit_access == vk::FALSE
// allocate and query again || a.storage_buffer16_bit_access != b.storage_buffer16_bit_access)
features2.features && (b.uniform_and_storage_buffer16_bit_access == vk::FALSE
}; || a.uniform_and_storage_buffer16_bit_access
this = this.features10(features); != b.uniform_and_storage_buffer16_bit_access)
&& (b.storage_push_constant16 == vk::FALSE
let extensions = unsafe { instance.enumerate_device_extension_properties(pdev)? }; || a.storage_push_constant16 != b.storage_push_constant16)
this = this.device_extensions(extensions); && (b.storage_input_output16 == vk::FALSE
|| a.storage_input_output16 != b.storage_input_output16)
Ok(this) && (b.multiview == vk::FALSE || a.multiview != b.multiview)
&& (b.multiview_geometry_shader == vk::FALSE
|| a.multiview_geometry_shader != b.multiview_geometry_shader)
&& (b.multiview_tessellation_shader == vk::FALSE
|| a.multiview_tessellation_shader != b.multiview_tessellation_shader)
&& (b.variable_pointers_storage_buffer == vk::FALSE
|| a.variable_pointers_storage_buffer != b.variable_pointers_storage_buffer)
&& (b.variable_pointers == vk::FALSE || a.variable_pointers != b.variable_pointers)
&& (b.protected_memory == vk::FALSE || a.protected_memory != b.protected_memory)
&& (b.sampler_ycbcr_conversion == vk::FALSE
|| a.sampler_ycbcr_conversion != b.sampler_ycbcr_conversion)
&& (b.shader_draw_parameters == vk::FALSE
|| a.shader_draw_parameters != b.shader_draw_parameters)
} }
fn features10(self, physical_features_10: vk::PhysicalDeviceFeatures) -> Self { fn core12_superset_of(
Self { a: &vk::PhysicalDeviceVulkan12Features,
physical_features_10, b: &vk::PhysicalDeviceVulkan12Features,
..self ) -> bool {
} (b.sampler_mirror_clamp_to_edge == vk::FALSE
} || a.sampler_mirror_clamp_to_edge != b.sampler_mirror_clamp_to_edge)
fn features11(self, physical_features_11: vk::PhysicalDeviceVulkan11Features<'static>) -> Self { && (b.draw_indirect_count == vk::FALSE
Self { || a.draw_indirect_count != b.draw_indirect_count)
physical_features_11: Some(physical_features_11), && (b.storage_buffer8_bit_access == vk::FALSE
..self || a.storage_buffer8_bit_access != b.storage_buffer8_bit_access)
} && (b.uniform_and_storage_buffer8_bit_access == vk::FALSE
} || a.uniform_and_storage_buffer8_bit_access
fn features12(self, physical_features_12: vk::PhysicalDeviceVulkan12Features<'static>) -> Self { != b.uniform_and_storage_buffer8_bit_access)
Self { && (b.storage_push_constant8 == vk::FALSE
physical_features_12: Some(physical_features_12), || a.storage_push_constant8 != b.storage_push_constant8)
..self && (b.shader_buffer_int64_atomics == vk::FALSE
} || a.shader_buffer_int64_atomics != b.shader_buffer_int64_atomics)
} && (b.shader_shared_int64_atomics == vk::FALSE
fn features13(self, physical_features_13: vk::PhysicalDeviceVulkan13Features<'static>) -> Self { || a.shader_shared_int64_atomics != b.shader_shared_int64_atomics)
Self { && (b.shader_float16 == vk::FALSE || a.shader_float16 != b.shader_float16)
physical_features_13: Some(physical_features_13), && (b.shader_int8 == vk::FALSE || a.shader_int8 != b.shader_int8)
..self && (b.descriptor_indexing == vk::FALSE
} || a.descriptor_indexing != b.descriptor_indexing)
} && (b.shader_input_attachment_array_dynamic_indexing == vk::FALSE
fn device_extensions(self, device_extensions: Vec<vk::ExtensionProperties>) -> Self { || a.shader_input_attachment_array_dynamic_indexing
Self { != b.shader_input_attachment_array_dynamic_indexing)
device_extensions, && (b.shader_uniform_texel_buffer_array_dynamic_indexing == vk::FALSE
..self || a.shader_uniform_texel_buffer_array_dynamic_indexing
} != b.shader_uniform_texel_buffer_array_dynamic_indexing)
&& (b.shader_storage_texel_buffer_array_dynamic_indexing == vk::FALSE
|| a.shader_storage_texel_buffer_array_dynamic_indexing
!= b.shader_storage_texel_buffer_array_dynamic_indexing)
&& (b.shader_uniform_buffer_array_non_uniform_indexing == vk::FALSE
|| a.shader_uniform_buffer_array_non_uniform_indexing
!= b.shader_uniform_buffer_array_non_uniform_indexing)
&& (b.shader_sampled_image_array_non_uniform_indexing == vk::FALSE
|| a.shader_sampled_image_array_non_uniform_indexing
!= b.shader_sampled_image_array_non_uniform_indexing)
&& (b.shader_storage_buffer_array_non_uniform_indexing == vk::FALSE
|| a.shader_storage_buffer_array_non_uniform_indexing
!= b.shader_storage_buffer_array_non_uniform_indexing)
&& (b.shader_storage_image_array_non_uniform_indexing == vk::FALSE
|| a.shader_storage_image_array_non_uniform_indexing
!= b.shader_storage_image_array_non_uniform_indexing)
&& (b.shader_input_attachment_array_non_uniform_indexing == vk::FALSE
|| a.shader_input_attachment_array_non_uniform_indexing
!= b.shader_input_attachment_array_non_uniform_indexing)
&& (b.shader_uniform_texel_buffer_array_non_uniform_indexing == vk::FALSE
|| a.shader_uniform_texel_buffer_array_non_uniform_indexing
!= b.shader_uniform_texel_buffer_array_non_uniform_indexing)
&& (b.shader_storage_texel_buffer_array_non_uniform_indexing == vk::FALSE
|| a.shader_storage_texel_buffer_array_non_uniform_indexing
!= b.shader_storage_texel_buffer_array_non_uniform_indexing)
&& (b.descriptor_binding_uniform_buffer_update_after_bind == vk::FALSE
|| a.descriptor_binding_uniform_buffer_update_after_bind
!= b.descriptor_binding_uniform_buffer_update_after_bind)
&& (b.descriptor_binding_sampled_image_update_after_bind == vk::FALSE
|| a.descriptor_binding_sampled_image_update_after_bind
!= b.descriptor_binding_sampled_image_update_after_bind)
&& (b.descriptor_binding_storage_image_update_after_bind == vk::FALSE
|| a.descriptor_binding_storage_image_update_after_bind
!= b.descriptor_binding_storage_image_update_after_bind)
&& (b.descriptor_binding_storage_buffer_update_after_bind == vk::FALSE
|| a.descriptor_binding_storage_buffer_update_after_bind
!= b.descriptor_binding_storage_buffer_update_after_bind)
&& (b.descriptor_binding_uniform_texel_buffer_update_after_bind == vk::FALSE
|| a.descriptor_binding_uniform_texel_buffer_update_after_bind
!= b.descriptor_binding_uniform_texel_buffer_update_after_bind)
&& (b.descriptor_binding_storage_texel_buffer_update_after_bind == vk::FALSE
|| a.descriptor_binding_storage_texel_buffer_update_after_bind
!= b.descriptor_binding_storage_texel_buffer_update_after_bind)
&& (b.descriptor_binding_update_unused_while_pending == vk::FALSE
|| a.descriptor_binding_update_unused_while_pending
!= b.descriptor_binding_update_unused_while_pending)
&& (b.descriptor_binding_partially_bound == vk::FALSE
|| a.descriptor_binding_partially_bound != b.descriptor_binding_partially_bound)
&& (b.descriptor_binding_variable_descriptor_count == vk::FALSE
|| a.descriptor_binding_variable_descriptor_count
!= b.descriptor_binding_variable_descriptor_count)
&& (b.runtime_descriptor_array == vk::FALSE
|| a.runtime_descriptor_array != b.runtime_descriptor_array)
&& (b.sampler_filter_minmax == vk::FALSE
|| a.sampler_filter_minmax != b.sampler_filter_minmax)
&& (b.scalar_block_layout == vk::FALSE
|| a.scalar_block_layout != b.scalar_block_layout)
&& (b.imageless_framebuffer == vk::FALSE
|| a.imageless_framebuffer != b.imageless_framebuffer)
&& (b.uniform_buffer_standard_layout == vk::FALSE
|| a.uniform_buffer_standard_layout != b.uniform_buffer_standard_layout)
&& (b.shader_subgroup_extended_types == vk::FALSE
|| a.shader_subgroup_extended_types != b.shader_subgroup_extended_types)
&& (b.separate_depth_stencil_layouts == vk::FALSE
|| a.separate_depth_stencil_layouts != b.separate_depth_stencil_layouts)
&& (b.host_query_reset == vk::FALSE || a.host_query_reset != b.host_query_reset)
&& (b.timeline_semaphore == vk::FALSE
|| a.timeline_semaphore != b.timeline_semaphore)
&& (b.buffer_device_address == vk::FALSE
|| a.buffer_device_address != b.buffer_device_address)
&& (b.buffer_device_address_capture_replay == vk::FALSE
|| a.buffer_device_address_capture_replay
!= b.buffer_device_address_capture_replay)
&& (b.buffer_device_address_multi_device == vk::FALSE
|| a.buffer_device_address_multi_device != b.buffer_device_address_multi_device)
&& (b.vulkan_memory_model == vk::FALSE
|| a.vulkan_memory_model != b.vulkan_memory_model)
&& (b.vulkan_memory_model_device_scope == vk::FALSE
|| a.vulkan_memory_model_device_scope != b.vulkan_memory_model_device_scope)
&& (b.vulkan_memory_model_availability_visibility_chains == vk::FALSE
|| a.vulkan_memory_model_availability_visibility_chains
!= b.vulkan_memory_model_availability_visibility_chains)
&& (b.shader_output_viewport_index == vk::FALSE
|| a.shader_output_viewport_index != b.shader_output_viewport_index)
&& (b.shader_output_layer == vk::FALSE
|| a.shader_output_layer != b.shader_output_layer)
&& (b.subgroup_broadcast_dynamic_id == vk::FALSE
|| a.subgroup_broadcast_dynamic_id != b.subgroup_broadcast_dynamic_id)
} }
#[allow(dead_code)] fn core13_superset_of(
fn with_extension2(mut self, ext: vk::ExtensionProperties) -> Self { a: &vk::PhysicalDeviceVulkan13Features,
self.device_extensions.push(ext); b: &vk::PhysicalDeviceVulkan13Features,
) -> bool {
self (b.robust_image_access == vk::FALSE || a.robust_image_access != b.robust_image_access)
&& (b.inline_uniform_block == vk::FALSE
|| a.inline_uniform_block != b.inline_uniform_block)
&& (b.descriptor_binding_inline_uniform_block_update_after_bind == vk::FALSE
|| a.descriptor_binding_inline_uniform_block_update_after_bind
!= b.descriptor_binding_inline_uniform_block_update_after_bind)
&& (b.pipeline_creation_cache_control == vk::FALSE
|| a.pipeline_creation_cache_control != b.pipeline_creation_cache_control)
&& (b.private_data == vk::FALSE || a.private_data != b.private_data)
&& (b.shader_demote_to_helper_invocation == vk::FALSE
|| a.shader_demote_to_helper_invocation != b.shader_demote_to_helper_invocation)
&& (b.shader_terminate_invocation == vk::FALSE
|| a.shader_terminate_invocation != b.shader_terminate_invocation)
&& (b.subgroup_size_control == vk::FALSE
|| a.subgroup_size_control != b.subgroup_size_control)
&& (b.compute_full_subgroups == vk::FALSE
|| a.compute_full_subgroups != b.compute_full_subgroups)
&& (b.synchronization2 == vk::FALSE || a.synchronization2 != b.synchronization2)
&& (b.texture_compression_astc_hdr == vk::FALSE
|| a.texture_compression_astc_hdr != b.texture_compression_astc_hdr)
&& (b.shader_zero_initialize_workgroup_memory == vk::FALSE
|| a.shader_zero_initialize_workgroup_memory
!= b.shader_zero_initialize_workgroup_memory)
&& (b.dynamic_rendering == vk::FALSE || a.dynamic_rendering != b.dynamic_rendering)
&& (b.shader_integer_dot_product == vk::FALSE
|| a.shader_integer_dot_product != b.shader_integer_dot_product)
&& (b.maintenance4 == vk::FALSE || a.maintenance4 != b.maintenance4)
} }
fn with_extensions2<I: IntoIterator<Item = vk::ExtensionProperties>>( fn mesh_shader_superset_of(
mut self, a: &vk::PhysicalDeviceMeshShaderFeaturesEXT,
exts: I, b: &vk::PhysicalDeviceMeshShaderFeaturesEXT,
) -> Self { ) -> bool {
self.device_extensions.extend(exts); (b.task_shader == vk::FALSE || a.task_shader != b.task_shader)
&& (b.mesh_shader == vk::FALSE || a.mesh_shader != b.mesh_shader)
self && (b.multiview_mesh_shader == vk::FALSE
|| a.multiview_mesh_shader != b.multiview_mesh_shader)
&& (b.primitive_fragment_shading_rate_mesh_shader == vk::FALSE
|| a.primitive_fragment_shading_rate_mesh_shader
!= b.primitive_fragment_shading_rate_mesh_shader)
&& (b.mesh_shader_queries == vk::FALSE
|| a.mesh_shader_queries != b.mesh_shader_queries)
} }
fn with_extension<F>(mut self, ext: vk::ExtensionProperties, features: F) -> Self core_superset_of(&self.core, &other.core)
where && core11_superset_of(&self.core11, &other.core11)
F: ExtendsDeviceFeatures2Debug + 'static, && core12_superset_of(&self.core12, &other.core12)
{ && core13_superset_of(&self.core13, &other.core13)
self.extra_features.push(Box::new(features)); && match (&self.mesh_shader, &other.mesh_shader) {
self.device_extensions.push(ext); (Some(a), Some(b)) => mesh_shader_superset_of(a, b),
(None, Some(_)) => false,
self _ => true,
} }
fn features2(&mut self) -> vk::PhysicalDeviceFeatures2<'_> {
let mut features2 =
vk::PhysicalDeviceFeatures2::default().features(self.physical_features_10);
if let Some(ref mut features11) = self.physical_features_11 {
features2 = features2.push_next(features11);
}
if let Some(ref mut features12) = self.physical_features_12 {
features2 = features2.push_next(features12);
}
if let Some(ref mut features13) = self.physical_features_13 {
features2 = features2.push_next(features13);
}
for features in self.extra_features.iter_mut() {
features2 = features2.push_next(Box::as_mut(features));
}
features2
}
fn supports_extension(&self, e: &vk::ExtensionProperties) -> bool {
self.device_extensions.iter().any(|ext| {
ext.extension_name_as_c_str() == e.extension_name_as_c_str()
&& ext.spec_version >= e.spec_version
})
}
fn compatible_with(&self, device: &Self) -> bool {
let sort_exts = |a: &vk::ExtensionProperties, b: &vk::ExtensionProperties| {
(a.extension_name_as_c_str().unwrap(), a.spec_version)
.cmp(&(b.extension_name_as_c_str().unwrap(), b.spec_version))
};
let mut device_extensions = device.device_extensions.clone();
device_extensions.sort_by(sort_exts);
let unsupported_extensions = self
.device_extensions
.iter()
.filter(|ext| {
device_extensions
.binary_search_by(|t| sort_exts(t, ext))
.is_err()
})
.cloned()
.collect::<Vec<_>>();
let supports_extensions = unsupported_extensions.is_empty();
supports_extensions
&& utils::eq_device_features10(
&utils::bitand_device_features10(
&self.physical_features_10,
&device.physical_features_10,
),
&self.physical_features_10,
)
&& self
.physical_features_11
.zip(device.physical_features_11)
.map(|(a, b)| {
utils::eq_device_features11(&utils::bitand_device_features11(&a, &b), &a)
})
.unwrap_or(true)
&& self
.physical_features_12
.zip(device.physical_features_12)
.map(|(a, b)| {
utils::eq_device_features12(&utils::bitand_device_features12(&a, &b), &a)
})
.unwrap_or(true)
&& self
.physical_features_13
.zip(device.physical_features_13)
.map(|(a, b)| {
utils::eq_device_features13(&utils::bitand_device_features13(&a, &b), &a)
})
.unwrap_or(true)
} }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct PhysicalDeviceProperties { pub(crate) struct PhysicalDeviceProperties {
base: vk::PhysicalDeviceProperties, /// Extensions supported by the device, as reported by `enumerate_device_extension_properties`.
vk11: vk::PhysicalDeviceVulkan11Properties<'static>, supported_extensions: Vec<vk::ExtensionProperties>,
vk12: vk::PhysicalDeviceVulkan12Properties<'static>, /// Vulkan 1.0 properties.
vk13: vk::PhysicalDeviceVulkan13Properties<'static>, core: vk::PhysicalDeviceProperties,
extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>, /// Vulkan 1.1 properties.
core11: vk::PhysicalDeviceVulkan11Properties<'static>,
/// Vulkan 1.2 properties.
core12: vk::PhysicalDeviceVulkan12Properties<'static>,
/// Vulkan 1.3 properties.
core13: vk::PhysicalDeviceVulkan13Properties<'static>,
/// Mesh shader properties from the `VK_EXT_mesh_shader` extension, if supported.
mesh_shader: Option<vk::PhysicalDeviceMeshShaderPropertiesEXT<'static>>,
/// Memory properties of the device, as reported by `get_physical_device_memory_properties`.
memory_properties: vk::PhysicalDeviceMemoryProperties,
/// The API version supported by the device.
device_api_version: u32,
} }
impl PhysicalDeviceProperties { impl PhysicalDeviceProperties {
fn query(&mut self, instance: &ash::Instance, pdev: vk::PhysicalDevice) { pub(crate) fn get_device_local_memory_count(&self) -> u64 {
let mut props2 = self.properties2(); self.memory_properties
.memory_heaps
.iter()
.filter(|heap| heap.flags.contains(vk::MemoryHeapFlags::DEVICE_LOCAL))
.map(|heap| heap.size)
.sum::<u64>()
}
}
fn get_physical_device_features(
instance: &InstanceInner,
pdev: vk::PhysicalDevice,
properties: &PhysicalDeviceProperties,
) -> Result<PhysicalDeviceFeatures> {
let mut features = PhysicalDeviceFeatures::default();
let mut features2 = vk::PhysicalDeviceFeatures2::default();
if properties.supports_extension(make_extension!(ext::mesh_shader)) {
features2 = features2.push_next(
features
.mesh_shader
.insert(vk::PhysicalDeviceMeshShaderFeaturesEXT::default()),
);
}
unsafe { unsafe {
instance.get_physical_device_properties2(pdev, &mut props2); instance
self.base = props2.properties; .raw
} .get_physical_device_features2(pdev, &mut features2);
} }
fn extra_properties( todo!()
mut self, }
extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
) -> Self {
self.extra_properties = extra_properties;
self
}
#[allow(dead_code)] fn get_physical_device_properties(
fn with_properties<F>(mut self, properties: F) -> Self instance: &InstanceInner,
where pdev: vk::PhysicalDevice,
F: ExtendsDeviceProperties2Debug + 'static, ) -> Result<PhysicalDeviceProperties> {
{ let mut props = PhysicalDeviceProperties::default();
self.extra_properties.push(Box::new(properties)); props.core = unsafe { instance.raw.get_physical_device_properties(pdev) };
props.device_api_version = props.core.api_version;
props.supported_extensions =
unsafe { instance.raw.enumerate_device_extension_properties(pdev)? };
props.memory_properties = unsafe { instance.raw.get_physical_device_memory_properties(pdev) };
self let supports_mesh_shader = props.supports_extension(make_extension!(ext::mesh_shader));
}
fn properties2(&mut self) -> vk::PhysicalDeviceProperties2<'_> { // TODO: fallibly check anything beyond 1.0
let mut props2 = vk::PhysicalDeviceProperties2::default() let mut props2 = vk::PhysicalDeviceProperties2::default()
.properties(self.base) .push_next(&mut props.core11)
.push_next(&mut self.vk11) .push_next(&mut props.core12)
.push_next(&mut self.vk12) .push_next(&mut props.core13);
.push_next(&mut self.vk13);
for props in &mut self.extra_properties { if supports_mesh_shader {
props2 = props2.push_next(Box::as_mut(props)); let next = props
.mesh_shader
.insert(vk::PhysicalDeviceMeshShaderPropertiesEXT::default());
props2 = props2.push_next(next);
} }
props2 unsafe {
instance
.raw
.get_physical_device_properties2(pdev, &mut props2);
}
Ok(props)
}
impl PhysicalDeviceProperties {
pub(crate) fn supports_extension(&self, e: Extension) -> bool {
self.supported_extensions
.iter()
.any(|ext| ext.extension_name_as_c_str() == Ok(e.name) && ext.spec_version >= e.version)
} }
} }
@ -788,6 +998,8 @@ impl Renderer2 {
pub use vk::Extent2D; pub use vk::Extent2D;
use crate::{device::Extension, instance::InstanceInner};
pub mod utils { pub mod utils {
#![allow(dead_code)] #![allow(dead_code)]

View file

@ -1,10 +1,11 @@
use std::{borrow::Cow, path::Path, sync::Arc}; use std::{borrow::Cow, path::Path, sync::Arc};
use ash::{prelude::*, vk}; use ash::{ext, prelude::*, vk};
use crate::{ use crate::{
define_device_owned_handle, define_device_owned_handle,
device::{Device, DeviceOwnedDebugObject}, device::{Device, DeviceOwnedDebugObject},
make_extension,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -303,13 +304,10 @@ impl DescriptorSetLayout {
.bindings(&bindings) .bindings(&bindings)
.flags(desc.flags); .flags(desc.flags);
if device.features().version >= vk::API_VERSION_1_2 if device.properties().device_api_version >= vk::API_VERSION_1_2
|| device || device
.features() .properties()
.supports_extension(&crate::make_extention_properties( .supports_extension(make_extension!(ext::descriptor_indexing))
ash::ext::descriptor_indexing::NAME,
ash::ext::descriptor_indexing::SPEC_VERSION,
))
{ {
info = info.push_next(flags); info = info.push_next(flags);
} }

View file

@ -0,0 +1,189 @@
use bitflags::bitflags;
use raw_window_handle::RawDisplayHandle;
use std::sync::{Arc, Mutex};
use ash::vk;
use crate::{Instance, PhysicalDeviceInfo, Result, instance::InstanceInner};
#[derive(Debug)]
pub struct Queue {
inner: Arc<QueueInner>,
}
#[derive(Debug)]
pub struct QueueInner {
queue: vk::Queue,
family: QueueFamily,
lock: Mutex<()>,
}
#[derive(Debug, Clone, Copy)]
pub struct QueueFamily {
pub index: u32,
pub count: u32,
pub flags: QueueFlags,
pub granularity: TransferGranuality,
pub timestamp_valid_bits: u32,
}
bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct QueueFlags: u16 {
const GRAPHICS = 0b1;
const COMPUTE = 0b10;
const TRANSFER = 0b100;
const PRESENT = 0b1000;
const ENCODE = 0b1_0000;
const DECODE = 0b10_0000;
}
}
impl QueueFlags {
pub fn from_vk_flags(vk_flags: vk::QueueFlags) -> Self {
let mut flags = QueueFlags::empty();
if vk_flags.contains(vk::QueueFlags::GRAPHICS) {
flags |= QueueFlags::GRAPHICS;
}
if vk_flags.contains(vk::QueueFlags::COMPUTE) {
flags |= QueueFlags::COMPUTE;
}
if vk_flags.contains(vk::QueueFlags::TRANSFER) {
flags |= QueueFlags::TRANSFER;
}
if vk_flags.contains(vk::QueueFlags::VIDEO_ENCODE_KHR) {
flags |= QueueFlags::ENCODE;
}
if vk_flags.contains(vk::QueueFlags::VIDEO_DECODE_KHR) {
flags |= QueueFlags::DECODE;
}
flags
}
}
#[derive(Debug, Clone, Copy)]
pub enum TransferGranuality {
FullImage,
Unrestricted,
Tiled(u32, u32, u32),
}
impl TransferGranuality {
pub fn from_vk_granularity(vk_granularity: vk::Extent3D) -> Self {
if vk_granularity.width == 0 || vk_granularity.height == 0 || vk_granularity.depth == 0 {
TransferGranuality::FullImage
} else if vk_granularity.width == 1
&& vk_granularity.height == 1
&& vk_granularity.depth == 1
{
TransferGranuality::Unrestricted
} else {
TransferGranuality::Tiled(
vk_granularity.width,
vk_granularity.height,
vk_granularity.depth,
)
}
}
}
#[derive(Debug)]
pub struct DeviceQueues {
graphics: Queue,
compute: Queue,
transfer: Queue,
}
#[derive(Debug)]
pub struct DeviceQueueInfos {
graphics: QueueFamily,
compute: Option<QueueFamily>,
transfer: Option<QueueFamily>,
}
impl DeviceQueueInfos {
pub fn select_queue_families(
instance: &Instance,
pdev: &PhysicalDeviceInfo,
display_handle: Option<RawDisplayHandle>,
) -> Result<Self> {
let queue_families = unsafe {
instance
.inner
.raw
.get_physical_device_queue_family_properties(pdev.pdev)
};
let queue_families = queue_families
.into_iter()
.enumerate()
.map(|(index, props)| {
let mut flags = QueueFlags::from_vk_flags(props.queue_flags);
if let Some(display_handle) = display_handle {
if instance.query_presentation_support(pdev.pdev, index as u32, display_handle)
{
flags |= QueueFlags::PRESENT;
}
}
QueueFamily {
index: index as u32,
count: props.queue_count,
flags,
granularity: TransferGranuality::from_vk_granularity(
props.min_image_transfer_granularity,
),
timestamp_valid_bits: props.timestamp_valid_bits,
}
})
.collect::<Vec<_>>();
let mut queue_counts = queue_families
.iter()
.map(|family| family.count)
.collect::<Vec<_>>();
let graphics = queue_families
.iter()
.enumerate()
.find(|(_, family)| {
family
.flags
.contains(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
})
.map(|(i, family)| {
queue_counts[i] -= 1;
*family
})
.expect("No graphics queue family found");
assert!(
graphics.flags.contains(QueueFlags::PRESENT),
"Selected graphics queue family does not support presentation"
);
let compute = queue_families
.iter()
.enumerate()
.find(|(i, family)| queue_counts[*i] > 0 && family.flags.contains(QueueFlags::COMPUTE))
.map(|(i, family)| {
queue_counts[i] -= 1;
*family
});
let transfer = queue_families
.iter()
.enumerate()
.find(|(i, family)| queue_counts[*i] > 0 && family.flags.contains(QueueFlags::TRANSFER))
.map(|(i, family)| {
queue_counts[i] -= 1;
*family
});
Ok(Self {
graphics,
compute,
transfer,
})
}
}

View file

@ -27,9 +27,9 @@ use derive_more::Debug;
#[derive(Debug)] #[derive(Debug)]
pub struct Surface { pub struct Surface {
raw: vk::SurfaceKHR, pub(crate) raw: vk::SurfaceKHR,
#[debug(skip)] #[debug(skip)]
functor: khr::surface::Instance, pub(crate) functor: khr::surface::Instance,
} }
impl Drop for Surface { impl Drop for Surface {