idk? pdev, queue refactor
This commit is contained in:
parent
20f743d74b
commit
05bf7dd61f
|
|
@ -16,8 +16,7 @@ use tinyvec::{ArrayVec, array_vec};
|
|||
|
||||
use crate::{
|
||||
Error, ExtendsDeviceProperties2Debug, Instance, PhysicalDevice, PhysicalDeviceFeatures,
|
||||
PhysicalDeviceProperties, Queue, Result, VkNameList, instance::InstanceInner,
|
||||
make_extention_properties, sync,
|
||||
PhysicalDeviceInfo, PhysicalDeviceProperties, Queue, Result, instance::InstanceInner, sync,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -127,6 +126,7 @@ pub struct DeviceInner {
|
|||
present_queue: Queue,
|
||||
sync_threadpool: sync::SyncThreadpool,
|
||||
features: crate::PhysicalDeviceFeatures,
|
||||
properties: crate::PhysicalDeviceProperties,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for DeviceInner {
|
||||
|
|
@ -175,7 +175,6 @@ pub struct DeviceDesc<'a> {
|
|||
pub layer_settings: &'a [vk::LayerSettingEXT<'a>],
|
||||
pub instance_extensions: &'a [Extension<'a>],
|
||||
pub display_handle: Option<RawDisplayHandle>,
|
||||
pub features: crate::PhysicalDeviceFeatures,
|
||||
}
|
||||
|
||||
const VALIDATION_LAYER_NAME: &core::ffi::CStr = c"VK_LAYER_KHRONOS_validation";
|
||||
|
|
@ -221,7 +220,6 @@ impl<'a> Default for DeviceDesc<'a> {
|
|||
layer_settings: &[],
|
||||
instance_extensions: 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>;
|
||||
|
||||
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> {
|
||||
let instance = Instance::new(&crate::instance::InstanceDesc {
|
||||
app_name: desc.app_name,
|
||||
|
|
@ -761,28 +707,29 @@ impl Device {
|
|||
display_handle: desc.display_handle,
|
||||
})?;
|
||||
|
||||
let mut features = desc.features.with_extension2(make_extention_properties(
|
||||
khr::swapchain::NAME,
|
||||
khr::swapchain::SPEC_VERSION,
|
||||
));
|
||||
|
||||
//these are required for the renderpass
|
||||
let features13 = features.physical_features_13.get_or_insert_default();
|
||||
features13.synchronization2 = vk::TRUE;
|
||||
features13.dynamic_rendering = vk::TRUE;
|
||||
features13.maintenance4 = vk::TRUE;
|
||||
// //these are required for the renderpass
|
||||
// let features13 = features.physical_features_13.get_or_insert_default();
|
||||
// features13.synchronization2 = vk::TRUE;
|
||||
// features13.dynamic_rendering = vk::TRUE;
|
||||
// features13.maintenance4 = vk::TRUE;
|
||||
let features = PhysicalDeviceFeatures {
|
||||
core13: vk::PhysicalDeviceVulkan13Features {
|
||||
synchronization2: vk::TRUE,
|
||||
dynamic_rendering: vk::TRUE,
|
||||
maintenance4: vk::TRUE,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Consider this: switching physical device in game?
|
||||
// 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.
|
||||
|
||||
let pdev = DeviceBuilder::choose_physical_device(
|
||||
&instance.inner,
|
||||
desc.display_handle,
|
||||
&features,
|
||||
vec![Box::new(
|
||||
vk::PhysicalDeviceMeshShaderPropertiesEXT::default(),
|
||||
)],
|
||||
let pdev = instance.choose_adapter_default(
|
||||
None,
|
||||
&[make_extension!(ext::mesh_shader)],
|
||||
Some(&features),
|
||||
)?;
|
||||
|
||||
tracing::trace!("pdev: {pdev:?}");
|
||||
|
|
@ -793,7 +740,7 @@ impl Device {
|
|||
|
||||
pub fn new(
|
||||
instance: Arc<InstanceInner>,
|
||||
physical: PhysicalDevice,
|
||||
physical: PhysicalDeviceInfo,
|
||||
mut features: crate::PhysicalDeviceFeatures,
|
||||
) -> VkResult<Self> {
|
||||
// we have 4 queues at most: graphics, compute, transfer, present
|
||||
|
|
@ -912,6 +859,9 @@ impl Device {
|
|||
pub fn features(&self) -> &crate::PhysicalDeviceFeatures {
|
||||
&self.0.features
|
||||
}
|
||||
pub fn properties(&self) -> &crate::PhysicalDeviceProperties {
|
||||
&self.0.properties
|
||||
}
|
||||
pub fn physical_device(&self) -> &PhysicalDevice {
|
||||
&self.0.physical
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
use std::{
|
||||
cmp::Ordering,
|
||||
ffi::{CStr, CString},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use ash::{Entry, ext, vk};
|
||||
use ash::{Entry, ext, khr, vk};
|
||||
use raw_window_handle::RawDisplayHandle;
|
||||
|
||||
use crate::{
|
||||
Error, PhysicalDeviceFeatures, PhysicalDeviceInfo,
|
||||
device::{Extension, get_extensions, get_layers},
|
||||
make_extension,
|
||||
get_physical_device_features, get_physical_device_properties, make_extension,
|
||||
swapchain::Surface,
|
||||
};
|
||||
|
||||
pub struct DebugUtilsCreateInfo {
|
||||
|
|
@ -155,6 +158,207 @@ impl 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 {
|
||||
|
|
|
|||
|
|
@ -8,14 +8,15 @@
|
|||
|
||||
use std::{collections::HashMap, ffi::CStr, fmt::Debug, marker::PhantomData, sync::Arc};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
|
||||
use ash::{
|
||||
Entry, ext,
|
||||
Entry, ext, khr,
|
||||
prelude::VkResult,
|
||||
vk::{self},
|
||||
vk::{self, SurfaceCapabilitiesKHR},
|
||||
};
|
||||
use dyn_clone::DynClone;
|
||||
|
||||
|
|
@ -84,6 +85,8 @@ use util::Rgba;
|
|||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("No Physical Device found for this instance.")]
|
||||
NoAdapter,
|
||||
#[error("Swapchain suboptimal.")]
|
||||
SuboptimalSwapchain,
|
||||
#[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)]
|
||||
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)]
|
||||
pub struct PhysicalDeviceFeatures {
|
||||
pub version: u32,
|
||||
pub physical_features_10: vk::PhysicalDeviceFeatures,
|
||||
pub physical_features_11: Option<vk::PhysicalDeviceVulkan11Features<'static>>,
|
||||
pub physical_features_12: Option<vk::PhysicalDeviceVulkan12Features<'static>>,
|
||||
pub physical_features_13: Option<vk::PhysicalDeviceVulkan13Features<'static>>,
|
||||
pub extra_features: Vec<Box<dyn ExtendsDeviceFeatures2Debug>>,
|
||||
pub device_extensions: Vec<vk::ExtensionProperties>,
|
||||
pub core: vk::PhysicalDeviceFeatures,
|
||||
pub core11: vk::PhysicalDeviceVulkan11Features<'static>,
|
||||
pub core12: vk::PhysicalDeviceVulkan12Features<'static>,
|
||||
pub core13: vk::PhysicalDeviceVulkan13Features<'static>,
|
||||
pub mesh_shader: Option<vk::PhysicalDeviceMeshShaderFeaturesEXT<'static>>,
|
||||
}
|
||||
|
||||
impl PhysicalDeviceFeatures {
|
||||
fn version(self, version: u32) -> Self {
|
||||
Self { version, ..self }
|
||||
}
|
||||
fn all_default() -> Self {
|
||||
Self::default()
|
||||
.features11(Default::default())
|
||||
.features12(Default::default())
|
||||
.features13(Default::default())
|
||||
pub fn superset_of(&self, other: &PhysicalDeviceFeatures) -> bool {
|
||||
fn core_superset_of(
|
||||
a: &vk::PhysicalDeviceFeatures,
|
||||
b: &vk::PhysicalDeviceFeatures,
|
||||
) -> bool {
|
||||
(b.robust_buffer_access == vk::FALSE
|
||||
|| a.robust_buffer_access != b.robust_buffer_access)
|
||||
&& (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> {
|
||||
let mut this = Self::all_default();
|
||||
let mut features2 = this.features2();
|
||||
let features = unsafe {
|
||||
instance.get_physical_device_features2(pdev, &mut features2);
|
||||
// allocate and query again
|
||||
features2.features
|
||||
};
|
||||
this = this.features10(features);
|
||||
|
||||
let extensions = unsafe { instance.enumerate_device_extension_properties(pdev)? };
|
||||
this = this.device_extensions(extensions);
|
||||
|
||||
Ok(this)
|
||||
fn core11_superset_of(
|
||||
a: &vk::PhysicalDeviceVulkan11Features,
|
||||
b: &vk::PhysicalDeviceVulkan11Features,
|
||||
) -> bool {
|
||||
(b.storage_buffer16_bit_access == vk::FALSE
|
||||
|| a.storage_buffer16_bit_access != b.storage_buffer16_bit_access)
|
||||
&& (b.uniform_and_storage_buffer16_bit_access == vk::FALSE
|
||||
|| a.uniform_and_storage_buffer16_bit_access
|
||||
!= b.uniform_and_storage_buffer16_bit_access)
|
||||
&& (b.storage_push_constant16 == vk::FALSE
|
||||
|| a.storage_push_constant16 != b.storage_push_constant16)
|
||||
&& (b.storage_input_output16 == vk::FALSE
|
||||
|| a.storage_input_output16 != b.storage_input_output16)
|
||||
&& (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 {
|
||||
Self {
|
||||
physical_features_10,
|
||||
..self
|
||||
}
|
||||
}
|
||||
fn features11(self, physical_features_11: vk::PhysicalDeviceVulkan11Features<'static>) -> Self {
|
||||
Self {
|
||||
physical_features_11: Some(physical_features_11),
|
||||
..self
|
||||
}
|
||||
}
|
||||
fn features12(self, physical_features_12: vk::PhysicalDeviceVulkan12Features<'static>) -> Self {
|
||||
Self {
|
||||
physical_features_12: Some(physical_features_12),
|
||||
..self
|
||||
}
|
||||
}
|
||||
fn features13(self, physical_features_13: vk::PhysicalDeviceVulkan13Features<'static>) -> Self {
|
||||
Self {
|
||||
physical_features_13: Some(physical_features_13),
|
||||
..self
|
||||
}
|
||||
}
|
||||
fn device_extensions(self, device_extensions: Vec<vk::ExtensionProperties>) -> Self {
|
||||
Self {
|
||||
device_extensions,
|
||||
..self
|
||||
}
|
||||
fn core12_superset_of(
|
||||
a: &vk::PhysicalDeviceVulkan12Features,
|
||||
b: &vk::PhysicalDeviceVulkan12Features,
|
||||
) -> bool {
|
||||
(b.sampler_mirror_clamp_to_edge == vk::FALSE
|
||||
|| a.sampler_mirror_clamp_to_edge != b.sampler_mirror_clamp_to_edge)
|
||||
&& (b.draw_indirect_count == vk::FALSE
|
||||
|| a.draw_indirect_count != b.draw_indirect_count)
|
||||
&& (b.storage_buffer8_bit_access == vk::FALSE
|
||||
|| 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
|
||||
!= b.uniform_and_storage_buffer8_bit_access)
|
||||
&& (b.storage_push_constant8 == vk::FALSE
|
||||
|| a.storage_push_constant8 != b.storage_push_constant8)
|
||||
&& (b.shader_buffer_int64_atomics == vk::FALSE
|
||||
|| a.shader_buffer_int64_atomics != b.shader_buffer_int64_atomics)
|
||||
&& (b.shader_shared_int64_atomics == vk::FALSE
|
||||
|| a.shader_shared_int64_atomics != b.shader_shared_int64_atomics)
|
||||
&& (b.shader_float16 == vk::FALSE || a.shader_float16 != b.shader_float16)
|
||||
&& (b.shader_int8 == vk::FALSE || a.shader_int8 != b.shader_int8)
|
||||
&& (b.descriptor_indexing == vk::FALSE
|
||||
|| a.descriptor_indexing != b.descriptor_indexing)
|
||||
&& (b.shader_input_attachment_array_dynamic_indexing == vk::FALSE
|
||||
|| a.shader_input_attachment_array_dynamic_indexing
|
||||
!= b.shader_input_attachment_array_dynamic_indexing)
|
||||
&& (b.shader_uniform_texel_buffer_array_dynamic_indexing == vk::FALSE
|
||||
|| 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 with_extension2(mut self, ext: vk::ExtensionProperties) -> Self {
|
||||
self.device_extensions.push(ext);
|
||||
|
||||
self
|
||||
fn core13_superset_of(
|
||||
a: &vk::PhysicalDeviceVulkan13Features,
|
||||
b: &vk::PhysicalDeviceVulkan13Features,
|
||||
) -> bool {
|
||||
(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>>(
|
||||
mut self,
|
||||
exts: I,
|
||||
) -> Self {
|
||||
self.device_extensions.extend(exts);
|
||||
|
||||
self
|
||||
fn mesh_shader_superset_of(
|
||||
a: &vk::PhysicalDeviceMeshShaderFeaturesEXT,
|
||||
b: &vk::PhysicalDeviceMeshShaderFeaturesEXT,
|
||||
) -> bool {
|
||||
(b.task_shader == vk::FALSE || a.task_shader != b.task_shader)
|
||||
&& (b.mesh_shader == vk::FALSE || a.mesh_shader != b.mesh_shader)
|
||||
&& (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
|
||||
where
|
||||
F: ExtendsDeviceFeatures2Debug + 'static,
|
||||
{
|
||||
self.extra_features.push(Box::new(features));
|
||||
self.device_extensions.push(ext);
|
||||
|
||||
self
|
||||
core_superset_of(&self.core, &other.core)
|
||||
&& core11_superset_of(&self.core11, &other.core11)
|
||||
&& core12_superset_of(&self.core12, &other.core12)
|
||||
&& core13_superset_of(&self.core13, &other.core13)
|
||||
&& match (&self.mesh_shader, &other.mesh_shader) {
|
||||
(Some(a), Some(b)) => mesh_shader_superset_of(a, b),
|
||||
(None, Some(_)) => false,
|
||||
_ => 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)]
|
||||
struct PhysicalDeviceProperties {
|
||||
base: vk::PhysicalDeviceProperties,
|
||||
vk11: vk::PhysicalDeviceVulkan11Properties<'static>,
|
||||
vk12: vk::PhysicalDeviceVulkan12Properties<'static>,
|
||||
vk13: vk::PhysicalDeviceVulkan13Properties<'static>,
|
||||
extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
|
||||
pub(crate) struct PhysicalDeviceProperties {
|
||||
/// Extensions supported by the device, as reported by `enumerate_device_extension_properties`.
|
||||
supported_extensions: Vec<vk::ExtensionProperties>,
|
||||
/// Vulkan 1.0 properties.
|
||||
core: vk::PhysicalDeviceProperties,
|
||||
/// 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 {
|
||||
fn query(&mut self, instance: &ash::Instance, pdev: vk::PhysicalDevice) {
|
||||
let mut props2 = self.properties2();
|
||||
pub(crate) fn get_device_local_memory_count(&self) -> u64 {
|
||||
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 {
|
||||
instance.get_physical_device_properties2(pdev, &mut props2);
|
||||
self.base = props2.properties;
|
||||
}
|
||||
instance
|
||||
.raw
|
||||
.get_physical_device_features2(pdev, &mut features2);
|
||||
}
|
||||
|
||||
fn extra_properties(
|
||||
mut self,
|
||||
extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
|
||||
) -> Self {
|
||||
self.extra_properties = extra_properties;
|
||||
self
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn with_properties<F>(mut self, properties: F) -> Self
|
||||
where
|
||||
F: ExtendsDeviceProperties2Debug + 'static,
|
||||
{
|
||||
self.extra_properties.push(Box::new(properties));
|
||||
fn get_physical_device_properties(
|
||||
instance: &InstanceInner,
|
||||
pdev: vk::PhysicalDevice,
|
||||
) -> Result<PhysicalDeviceProperties> {
|
||||
let mut props = PhysicalDeviceProperties::default();
|
||||
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()
|
||||
.properties(self.base)
|
||||
.push_next(&mut self.vk11)
|
||||
.push_next(&mut self.vk12)
|
||||
.push_next(&mut self.vk13);
|
||||
.push_next(&mut props.core11)
|
||||
.push_next(&mut props.core12)
|
||||
.push_next(&mut props.core13);
|
||||
|
||||
for props in &mut self.extra_properties {
|
||||
props2 = props2.push_next(Box::as_mut(props));
|
||||
if supports_mesh_shader {
|
||||
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;
|
||||
|
||||
use crate::{device::Extension, instance::InstanceInner};
|
||||
|
||||
pub mod utils {
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use std::{borrow::Cow, path::Path, sync::Arc};
|
||||
|
||||
use ash::{prelude::*, vk};
|
||||
use ash::{ext, prelude::*, vk};
|
||||
|
||||
use crate::{
|
||||
define_device_owned_handle,
|
||||
device::{Device, DeviceOwnedDebugObject},
|
||||
make_extension,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -303,13 +304,10 @@ impl DescriptorSetLayout {
|
|||
.bindings(&bindings)
|
||||
.flags(desc.flags);
|
||||
|
||||
if device.features().version >= vk::API_VERSION_1_2
|
||||
if device.properties().device_api_version >= vk::API_VERSION_1_2
|
||||
|| device
|
||||
.features()
|
||||
.supports_extension(&crate::make_extention_properties(
|
||||
ash::ext::descriptor_indexing::NAME,
|
||||
ash::ext::descriptor_indexing::SPEC_VERSION,
|
||||
))
|
||||
.properties()
|
||||
.supports_extension(make_extension!(ext::descriptor_indexing))
|
||||
{
|
||||
info = info.push_next(flags);
|
||||
}
|
||||
|
|
|
|||
189
crates/renderer/src/queue.rs
Normal file
189
crates/renderer/src/queue.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -27,9 +27,9 @@ use derive_more::Debug;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Surface {
|
||||
raw: vk::SurfaceKHR,
|
||||
pub(crate) raw: vk::SurfaceKHR,
|
||||
#[debug(skip)]
|
||||
functor: khr::surface::Instance,
|
||||
pub(crate) functor: khr::surface::Instance,
|
||||
}
|
||||
|
||||
impl Drop for Surface {
|
||||
|
|
|
|||
Loading…
Reference in a new issue