instance refactor
This commit is contained in:
parent
41e4a2ed9c
commit
20f743d74b
|
|
@ -16,7 +16,8 @@ use tinyvec::{ArrayVec, array_vec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Error, ExtendsDeviceProperties2Debug, Instance, PhysicalDevice, PhysicalDeviceFeatures,
|
Error, ExtendsDeviceProperties2Debug, Instance, PhysicalDevice, PhysicalDeviceFeatures,
|
||||||
PhysicalDeviceProperties, Queue, Result, VkNameList, make_extention_properties, sync,
|
PhysicalDeviceProperties, Queue, Result, VkNameList, instance::InstanceInner,
|
||||||
|
make_extention_properties, sync,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
|
@ -114,7 +115,7 @@ pub struct DeviceInner {
|
||||||
alloc: vk_mem::Allocator,
|
alloc: vk_mem::Allocator,
|
||||||
device: DeviceWrapper,
|
device: DeviceWrapper,
|
||||||
physical: PhysicalDevice,
|
physical: PhysicalDevice,
|
||||||
instance: Arc<Instance>,
|
instance: Arc<InstanceInner>,
|
||||||
swapchain: khr::swapchain::Device,
|
swapchain: khr::swapchain::Device,
|
||||||
debug_utils: ash::ext::debug_utils::Device,
|
debug_utils: ash::ext::debug_utils::Device,
|
||||||
allocated_queues: BTreeMap<(u32, u32), Queue>,
|
allocated_queues: BTreeMap<(u32, u32), Queue>,
|
||||||
|
|
@ -137,18 +138,18 @@ impl core::fmt::Debug for DeviceInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! make_extention {
|
macro_rules! make_extension {
|
||||||
($module:path) => {{
|
($module:path) => {{
|
||||||
use $module::{NAME as EXTENSION_NAME, SPEC_VERSION as EXTENSION_VERSION};
|
use $module::{NAME as EXTENSION_NAME, SPEC_VERSION as EXTENSION_VERSION};
|
||||||
Extension {
|
$crate::device::Extension {
|
||||||
name: EXTENSION_NAME.to_str().unwrap(),
|
name: EXTENSION_NAME,
|
||||||
version: EXTENSION_VERSION,
|
version: EXTENSION_VERSION,
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
($module:path as $version:expr) => {{
|
($module:path as $version:expr) => {{
|
||||||
use $module::*;
|
use $module::*;
|
||||||
Extension {
|
$crate::device::Extension {
|
||||||
name: NAME.to_str().unwrap(),
|
name: NAME,
|
||||||
version: $version,
|
version: $version,
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
@ -156,7 +157,7 @@ macro_rules! make_extention {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Extension<'a> {
|
pub struct Extension<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a CStr,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,7 +230,7 @@ struct DeviceBuilder;
|
||||||
|
|
||||||
impl DeviceBuilder {
|
impl DeviceBuilder {
|
||||||
fn queue_family_supports_presentation(
|
fn queue_family_supports_presentation(
|
||||||
instance: &Instance,
|
instance: &Arc<InstanceInner>,
|
||||||
pdev: vk::PhysicalDevice,
|
pdev: vk::PhysicalDevice,
|
||||||
queue_family: u32,
|
queue_family: u32,
|
||||||
display_handle: RawDisplayHandle,
|
display_handle: RawDisplayHandle,
|
||||||
|
|
@ -270,7 +271,7 @@ impl DeviceBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_pdev_queue_families(
|
fn select_pdev_queue_families(
|
||||||
instance: &Instance,
|
instance: &Arc<InstanceInner>,
|
||||||
display_handle: Option<RawDisplayHandle>,
|
display_handle: Option<RawDisplayHandle>,
|
||||||
pdev: vk::PhysicalDevice,
|
pdev: vk::PhysicalDevice,
|
||||||
) -> DeviceQueueFamilies {
|
) -> DeviceQueueFamilies {
|
||||||
|
|
@ -454,7 +455,7 @@ impl DeviceBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn choose_physical_device(
|
fn choose_physical_device(
|
||||||
instance: &Instance,
|
instance: &Arc<InstanceInner>,
|
||||||
display_handle: Option<RawDisplayHandle>,
|
display_handle: Option<RawDisplayHandle>,
|
||||||
requirements: &PhysicalDeviceFeatures,
|
requirements: &PhysicalDeviceFeatures,
|
||||||
extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
|
extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
|
||||||
|
|
@ -505,173 +506,187 @@ impl DeviceBuilder {
|
||||||
properties,
|
properties,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_available_extensions(
|
pub(crate) fn get_available_extensions(
|
||||||
entry: &ash::Entry,
|
entry: &ash::Entry,
|
||||||
layers: &[&CStr],
|
layers: &[&CStr],
|
||||||
) -> Result<Vec<ash::vk::ExtensionProperties>> {
|
) -> Result<Vec<ash::vk::ExtensionProperties>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let extensions = core::iter::once(entry.enumerate_instance_extension_properties(None))
|
let extensions = core::iter::once(entry.enumerate_instance_extension_properties(None))
|
||||||
.chain(
|
.chain(
|
||||||
layers
|
layers
|
||||||
.iter()
|
|
||||||
.map(|&layer| entry.enumerate_instance_extension_properties(Some(layer))),
|
|
||||||
)
|
|
||||||
.filter_map(|result| result.ok())
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<ash::vk::ExtensionProperties>>();
|
|
||||||
|
|
||||||
Ok(extensions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns a tuple of supported-or-enabled extensions and unsupported-and-requested extensions
|
|
||||||
fn get_extensions<'a>(
|
|
||||||
entry: &ash::Entry,
|
|
||||||
layers: &[&'a CStr],
|
|
||||||
extensions: impl Iterator<Item = Extension<'a>> + 'a,
|
|
||||||
display_handle: Option<RawDisplayHandle>,
|
|
||||||
) -> Result<(HashSet<Extension<'a>>, HashSet<Extension<'a>>)> {
|
|
||||||
unsafe {
|
|
||||||
let available_extensions = Self::get_available_extensions(entry, layers)?;
|
|
||||||
|
|
||||||
let available_extension_names = available_extensions
|
|
||||||
.iter()
|
|
||||||
.filter_map(|ext| {
|
|
||||||
Some((
|
|
||||||
ext.extension_name_as_c_str().ok()?.to_str().ok()?,
|
|
||||||
ext.spec_version,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"Available extensions: {:?}",
|
|
||||||
available_extension_names.iter().collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut out_extensions = HashSet::new();
|
|
||||||
let mut unsupported_extensions = HashSet::new();
|
|
||||||
|
|
||||||
let mut wsi_extensions = Vec::new();
|
|
||||||
wsi_extensions.push(make_extention!(khr::surface));
|
|
||||||
|
|
||||||
// taken from wgpu-hal/src/vulkan/instance.rs:
|
|
||||||
if cfg!(all(
|
|
||||||
unix,
|
|
||||||
not(target_os = "android"),
|
|
||||||
not(target_os = "macos")
|
|
||||||
)) {
|
|
||||||
wsi_extensions.push(make_extention!(khr::xlib_surface));
|
|
||||||
wsi_extensions.push(make_extention!(khr::xcb_surface));
|
|
||||||
wsi_extensions.push(make_extention!(khr::wayland_surface));
|
|
||||||
}
|
|
||||||
if cfg!(target_os = "windows") {
|
|
||||||
wsi_extensions.push(make_extention!(khr::win32_surface));
|
|
||||||
}
|
|
||||||
if cfg!(target_os = "android") {
|
|
||||||
wsi_extensions.push(make_extention!(khr::android_surface));
|
|
||||||
}
|
|
||||||
if cfg!(target_os = "macos") {
|
|
||||||
wsi_extensions.push(make_extention!(ext::metal_surface));
|
|
||||||
wsi_extensions.push(make_extention!(khr::portability_enumeration));
|
|
||||||
}
|
|
||||||
if cfg!(all(
|
|
||||||
unix,
|
|
||||||
not(target_vendor = "apple"),
|
|
||||||
not(target_family = "wasm")
|
|
||||||
)) {
|
|
||||||
wsi_extensions.push(make_extention!(ext::acquire_drm_display));
|
|
||||||
wsi_extensions.push(make_extention!(ext::direct_mode_display));
|
|
||||||
wsi_extensions.push(make_extention!(khr::display));
|
|
||||||
}
|
|
||||||
|
|
||||||
for extension in extensions {
|
|
||||||
if let Some(available_version) = available_extension_names.get(&extension.name)
|
|
||||||
&& *available_version >= extension.version
|
|
||||||
{
|
|
||||||
out_extensions.insert(extension);
|
|
||||||
} else {
|
|
||||||
unsupported_extensions.insert(extension);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for extension in wsi_extensions {
|
|
||||||
if let Some(available_version) = available_extension_names.get(&extension.name)
|
|
||||||
&& *available_version >= extension.version
|
|
||||||
{
|
|
||||||
out_extensions.insert(extension);
|
|
||||||
}
|
|
||||||
// don't warn about missing WSI extensions, these might not all
|
|
||||||
// be needed and weren't requested by the user.
|
|
||||||
}
|
|
||||||
|
|
||||||
// if a display handle is provided, ensure the required WSI extensions are present
|
|
||||||
let required_extension_names = display_handle
|
|
||||||
.map(ash_window::enumerate_required_extensions)
|
|
||||||
.unwrap_or(Ok(&[]))?;
|
|
||||||
|
|
||||||
for &extension in required_extension_names {
|
|
||||||
let extension = core::ffi::CStr::from_ptr(extension);
|
|
||||||
let extension = Extension {
|
|
||||||
name: extension.to_str()?,
|
|
||||||
version: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(available_version) = available_extension_names.get(&extension.name)
|
|
||||||
&& *available_version >= extension.version
|
|
||||||
{
|
|
||||||
out_extensions.insert(extension);
|
|
||||||
} else {
|
|
||||||
unsupported_extensions.insert(extension);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((out_extensions, unsupported_extensions))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_layers<'a>(
|
|
||||||
entry: &ash::Entry,
|
|
||||||
wants_layers: impl Iterator<Item = &'a CStr> + 'a,
|
|
||||||
) -> core::result::Result<Vec<&'a CStr>, (Vec<&'a CStr>, Vec<&'a CStr>)> {
|
|
||||||
unsafe {
|
|
||||||
let wants_layers = wants_layers.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let available_layers = entry
|
|
||||||
.enumerate_instance_layer_properties()
|
|
||||||
.map_err(|_| (Vec::<&'a CStr>::new(), wants_layers.clone()))?;
|
|
||||||
let available_layer_names = available_layers
|
|
||||||
.iter()
|
|
||||||
.map(|layer| layer.layer_name_as_c_str())
|
|
||||||
.collect::<core::result::Result<BTreeSet<_>, _>>()
|
|
||||||
.map_err(|_| (Vec::<&'a CStr>::new(), wants_layers.clone()))?;
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"Available layers: {:?}",
|
|
||||||
available_layer_names
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_str().unwrap_or("<invalid utf8>"))
|
.map(|&layer| entry.enumerate_instance_extension_properties(Some(layer))),
|
||||||
.collect::<Vec<_>>()
|
)
|
||||||
|
.filter_map(|result| result.ok())
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<ash::vk::ExtensionProperties>>();
|
||||||
|
|
||||||
|
Ok(extensions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns a tuple of supported-or-enabled extensions and unsupported-and-requested extensions
|
||||||
|
pub(crate) fn get_extensions<'a>(
|
||||||
|
entry: &ash::Entry,
|
||||||
|
layers: &[&'a CStr],
|
||||||
|
mut extensions: Vec<Extension<'a>>,
|
||||||
|
display_handle: Option<RawDisplayHandle>,
|
||||||
|
) -> Result<(HashSet<Extension<'a>>, HashSet<Extension<'a>>)> {
|
||||||
|
let available_extensions = get_available_extensions(entry, layers)?;
|
||||||
|
|
||||||
|
let available_extension_names = available_extensions
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ext| {
|
||||||
|
Some((
|
||||||
|
ext.extension_name_as_c_str().ok()?.to_str().ok()?,
|
||||||
|
ext.spec_version,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"Available extensions: {:?}",
|
||||||
|
available_extension_names.iter().collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut wsi_extensions = Vec::new();
|
||||||
|
wsi_extensions.push(make_extension!(khr::surface));
|
||||||
|
|
||||||
|
// taken from wgpu-hal/src/vulkan/instance.rs:
|
||||||
|
//
|
||||||
|
// we want to enable all the wsi extensions that are applicable to the
|
||||||
|
// platform, even if the user didn't explicitly request them, or
|
||||||
|
// supplied a different/no display handle, because we might later want
|
||||||
|
// to create a surface for a different windowing system, and enabling
|
||||||
|
// all the wsi extensions doesn't have any real downsides.
|
||||||
|
// We don't notify the user if some of these extensions aren't available
|
||||||
|
// (e.g. because wayland isn't supported on some unix system)
|
||||||
|
if cfg!(all(
|
||||||
|
unix,
|
||||||
|
not(target_os = "android"),
|
||||||
|
not(target_os = "macos")
|
||||||
|
)) {
|
||||||
|
wsi_extensions.push(make_extension!(khr::xlib_surface));
|
||||||
|
wsi_extensions.push(make_extension!(khr::xcb_surface));
|
||||||
|
wsi_extensions.push(make_extension!(khr::wayland_surface));
|
||||||
|
}
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
wsi_extensions.push(make_extension!(khr::win32_surface));
|
||||||
|
}
|
||||||
|
if cfg!(target_os = "android") {
|
||||||
|
wsi_extensions.push(make_extension!(khr::android_surface));
|
||||||
|
}
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
wsi_extensions.push(make_extension!(ext::metal_surface));
|
||||||
|
wsi_extensions.push(make_extension!(khr::portability_enumeration));
|
||||||
|
}
|
||||||
|
if cfg!(all(
|
||||||
|
unix,
|
||||||
|
not(target_vendor = "apple"),
|
||||||
|
not(target_family = "wasm")
|
||||||
|
)) {
|
||||||
|
wsi_extensions.push(make_extension!(ext::acquire_drm_display));
|
||||||
|
wsi_extensions.push(make_extension!(ext::direct_mode_display));
|
||||||
|
wsi_extensions.push(make_extension!(khr::display));
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_extension_available = |ext: &mut Extension| -> bool {
|
||||||
|
if available_extensions
|
||||||
|
.iter()
|
||||||
|
.any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext.name))
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
tracing::warn!(
|
||||||
|
"Extension {:?} v{} was requested but is not available",
|
||||||
|
ext.name,
|
||||||
|
ext.version
|
||||||
);
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut out_layers = Vec::new();
|
let mut enabled_extensions = extensions
|
||||||
let mut unsupported_layers = Vec::new();
|
.extract_if(.., is_extension_available)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for layer in wants_layers {
|
enabled_extensions.extend(wsi_extensions.extract_if(.., is_extension_available));
|
||||||
if available_layer_names.contains(&layer) {
|
|
||||||
out_layers.push(layer);
|
|
||||||
} else {
|
|
||||||
unsupported_layers.push(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !unsupported_layers.is_empty() {
|
// if a display handle is provided, ensure the required WSI extensions are present
|
||||||
Err((out_layers, unsupported_layers))
|
if let Some(display_handle) = display_handle {
|
||||||
|
let mut required_extensions = ash_window::enumerate_required_extensions(display_handle)?
|
||||||
|
.iter()
|
||||||
|
.map(|&p| Extension {
|
||||||
|
name: unsafe { CStr::from_ptr(p) },
|
||||||
|
version: 0,
|
||||||
|
})
|
||||||
|
// filter out extensions that are already enabled
|
||||||
|
.filter(|ext| {
|
||||||
|
!enabled_extensions
|
||||||
|
.iter()
|
||||||
|
.any(|enabled| enabled.name == ext.name)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// filter out extensions that aren't available, and log a warning for them
|
||||||
|
let display_extensions = required_extensions.extract_if(.., is_extension_available);
|
||||||
|
|
||||||
|
enabled_extensions.extend(display_extensions);
|
||||||
|
extensions.extend(required_extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// all extensions remaining in `extensions` at this point are unsupported,
|
||||||
|
// and were requested by the user or are required by the display handle
|
||||||
|
let unsupported_extensions = HashSet::from_iter(extensions);
|
||||||
|
let out_extensions = HashSet::from_iter(enabled_extensions);
|
||||||
|
|
||||||
|
Ok((out_extensions, unsupported_extensions))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns a list of enabled, or a tuple of enabled and unsupported but requested layers.
|
||||||
|
pub(crate) fn get_layers<'a>(
|
||||||
|
entry: &ash::Entry,
|
||||||
|
wants_layers: Vec<&'a CStr>,
|
||||||
|
) -> core::result::Result<Vec<&'a CStr>, (Vec<&'a CStr>, Vec<&'a CStr>)> {
|
||||||
|
unsafe {
|
||||||
|
let Ok(available_layers) = entry.enumerate_instance_layer_properties() else {
|
||||||
|
return Err((vec![], wants_layers));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(available_layer_names) = available_layers
|
||||||
|
.iter()
|
||||||
|
.map(|layer| layer.layer_name_as_c_str())
|
||||||
|
.collect::<core::result::Result<BTreeSet<_>, _>>()
|
||||||
|
else {
|
||||||
|
return Err((vec![], wants_layers));
|
||||||
|
};
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"Available layers: {:?}",
|
||||||
|
available_layer_names
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_str().unwrap_or("<invalid utf8>"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut enabled_layers = Vec::new();
|
||||||
|
let mut unsupported_layers = Vec::new();
|
||||||
|
|
||||||
|
for layer in wants_layers {
|
||||||
|
if available_layer_names.contains(&layer) {
|
||||||
|
enabled_layers.push(layer);
|
||||||
} else {
|
} else {
|
||||||
Ok(out_layers)
|
unsupported_layers.push(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !unsupported_layers.is_empty() {
|
||||||
|
Err((enabled_layers, unsupported_layers))
|
||||||
|
} else {
|
||||||
|
Ok(enabled_layers)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -733,92 +748,18 @@ impl Device {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn new_from_desc(desc: DeviceDesc) -> crate::Result<Self> {
|
pub fn new_from_desc(desc: DeviceDesc) -> crate::Result<Self> {
|
||||||
tracing::debug!("creating new device with: {desc:#?}");
|
let instance = Instance::new(&crate::instance::InstanceDesc {
|
||||||
let entry = unsafe { ash::Entry::load()? };
|
app_name: desc.app_name,
|
||||||
|
app_version: desc.app_version,
|
||||||
let app_name = desc
|
instance_extensions: &desc
|
||||||
.app_name
|
.instance_extensions
|
||||||
.and_then(|name| CString::new(name).ok())
|
|
||||||
.unwrap_or(c"ShooterGame".to_owned());
|
|
||||||
|
|
||||||
let app_info = vk::ApplicationInfo::default()
|
|
||||||
.api_version(desc.features.version)
|
|
||||||
.application_name(&app_name)
|
|
||||||
.application_version(desc.app_version)
|
|
||||||
.engine_name(c"VidyaEngine")
|
|
||||||
.engine_version(vk::make_api_version(0, 0, 1, 0));
|
|
||||||
|
|
||||||
let mut validation_info =
|
|
||||||
vk::LayerSettingsCreateInfoEXT::default().settings(desc.layer_settings);
|
|
||||||
|
|
||||||
let extra_instance_extensions = [
|
|
||||||
make_extention!(ext::debug_utils as 1),
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
make_extention!(ext::layer_settings),
|
|
||||||
];
|
|
||||||
|
|
||||||
let layers = DeviceBuilder::get_layers(&entry, desc.layers.iter().cloned()).unwrap();
|
|
||||||
|
|
||||||
let (extensions, unsupported_extensions) = DeviceBuilder::get_extensions(
|
|
||||||
&entry,
|
|
||||||
&layers,
|
|
||||||
desc.instance_extensions
|
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.map(|ext| ext.name)
|
||||||
.chain(extra_instance_extensions),
|
.collect::<Vec<_>>(),
|
||||||
desc.display_handle,
|
layers: desc.layers,
|
||||||
)?;
|
layer_settings: desc.layer_settings,
|
||||||
|
display_handle: desc.display_handle,
|
||||||
if !unsupported_extensions.is_empty() {
|
})?;
|
||||||
tracing::error!(
|
|
||||||
"extensions were requested but not supported by instance: {:?}",
|
|
||||||
unsupported_extensions
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let layers = VkNameList::from_strs(&layers);
|
|
||||||
let extensions = crate::util::CStringList::from_iter(extensions.iter().map(|ext| ext.name));
|
|
||||||
|
|
||||||
let create_info = vk::InstanceCreateInfo::default()
|
|
||||||
.application_info(&app_info)
|
|
||||||
.enabled_extension_names(&extensions.strings)
|
|
||||||
.enabled_layer_names(&layers.names)
|
|
||||||
.push_next(&mut validation_info);
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"Creating instance:\napp_info: {app_info:#?}\ncreate_info: {create_info:#?}"
|
|
||||||
);
|
|
||||||
|
|
||||||
let instance = unsafe { entry.create_instance(&create_info, None)? };
|
|
||||||
|
|
||||||
let debug_utils = {
|
|
||||||
let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default()
|
|
||||||
.message_severity(
|
|
||||||
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR
|
|
||||||
| vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
|
|
||||||
| vk::DebugUtilsMessageSeverityFlagsEXT::INFO,
|
|
||||||
)
|
|
||||||
.message_type(
|
|
||||||
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
|
|
||||||
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
|
|
||||||
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
|
|
||||||
)
|
|
||||||
.pfn_user_callback(Some(crate::debug::debug_callback));
|
|
||||||
|
|
||||||
let instance = ext::debug_utils::Instance::new(&entry, &instance);
|
|
||||||
let messenger = unsafe { instance.create_debug_utils_messenger(&debug_info, None)? };
|
|
||||||
|
|
||||||
crate::DebugUtils {
|
|
||||||
instance,
|
|
||||||
messenger,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let instance = Arc::new(Instance {
|
|
||||||
raw: instance,
|
|
||||||
_debug_utils: debug_utils,
|
|
||||||
entry,
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut features = desc.features.with_extension2(make_extention_properties(
|
let mut features = desc.features.with_extension2(make_extention_properties(
|
||||||
khr::swapchain::NAME,
|
khr::swapchain::NAME,
|
||||||
|
|
@ -836,7 +777,7 @@ impl Device {
|
||||||
// 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 = DeviceBuilder::choose_physical_device(
|
||||||
&instance,
|
&instance.inner,
|
||||||
desc.display_handle,
|
desc.display_handle,
|
||||||
&features,
|
&features,
|
||||||
vec![Box::new(
|
vec![Box::new(
|
||||||
|
|
@ -845,13 +786,13 @@ impl Device {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
tracing::trace!("pdev: {pdev:?}");
|
tracing::trace!("pdev: {pdev:?}");
|
||||||
let device = Device::new(instance.clone(), pdev, features)?;
|
let device = Device::new(instance.inner.clone(), pdev, features)?;
|
||||||
|
|
||||||
Ok(device)
|
Ok(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
instance: Arc<Instance>,
|
instance: Arc<InstanceInner>,
|
||||||
physical: PhysicalDevice,
|
physical: PhysicalDevice,
|
||||||
mut features: crate::PhysicalDeviceFeatures,
|
mut features: crate::PhysicalDeviceFeatures,
|
||||||
) -> VkResult<Self> {
|
) -> VkResult<Self> {
|
||||||
|
|
@ -953,7 +894,7 @@ impl Device {
|
||||||
pub fn dev(&self) -> &ash::Device {
|
pub fn dev(&self) -> &ash::Device {
|
||||||
&self.0.device
|
&self.0.device
|
||||||
}
|
}
|
||||||
pub fn instance(&self) -> &Arc<Instance> {
|
pub fn instance(&self) -> &Arc<InstanceInner> {
|
||||||
&self.0.instance
|
&self.0.instance
|
||||||
}
|
}
|
||||||
pub fn swapchain(&self) -> &khr::swapchain::Device {
|
pub fn swapchain(&self) -> &khr::swapchain::Device {
|
||||||
|
|
|
||||||
|
|
@ -1 +1,172 @@
|
||||||
|
use std::{
|
||||||
|
ffi::{CStr, CString},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use ash::{Entry, ext, vk};
|
||||||
|
use raw_window_handle::RawDisplayHandle;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
device::{Extension, get_extensions, get_layers},
|
||||||
|
make_extension,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct DebugUtilsCreateInfo {
|
||||||
|
pub severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||||
|
pub message_type: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InstanceInner {
|
||||||
|
pub raw: ash::Instance,
|
||||||
|
pub entry: Entry,
|
||||||
|
pub(crate) _debug_utils: DebugUtils,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Instance {
|
||||||
|
pub(crate) inner: Arc<InstanceInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Debug for Instance {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Instance")
|
||||||
|
.field("raw", &self.inner.raw.handle())
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InstanceDesc<'a> {
|
||||||
|
pub app_name: Option<&'a str>,
|
||||||
|
pub app_version: u32,
|
||||||
|
pub instance_extensions: &'a [&'a CStr],
|
||||||
|
pub layer_settings: &'a [vk::LayerSettingEXT<'a>],
|
||||||
|
pub layers: &'a [&'a CStr],
|
||||||
|
pub display_handle: Option<RawDisplayHandle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance {
|
||||||
|
pub fn new<'a>(desc: &InstanceDesc<'a>) -> crate::Result<Self> {
|
||||||
|
let entry = unsafe { ash::Entry::load()? };
|
||||||
|
|
||||||
|
let app_name = desc
|
||||||
|
.app_name
|
||||||
|
.and_then(|name| CString::new(name).ok())
|
||||||
|
.unwrap_or(c"ShooterGame".to_owned());
|
||||||
|
|
||||||
|
let version =
|
||||||
|
unsafe { entry.try_enumerate_instance_version()? }.unwrap_or(vk::API_VERSION_1_0);
|
||||||
|
|
||||||
|
let app_info = vk::ApplicationInfo::default()
|
||||||
|
.api_version(if version < vk::API_VERSION_1_1 {
|
||||||
|
vk::API_VERSION_1_0
|
||||||
|
} else {
|
||||||
|
// ash doesn't support 1.4 yet
|
||||||
|
vk::API_VERSION_1_3
|
||||||
|
})
|
||||||
|
.application_name(&app_name)
|
||||||
|
.application_version(desc.app_version)
|
||||||
|
.engine_name(c"Bevy Engine")
|
||||||
|
.engine_version(vk::make_api_version(0, 0, 1, 0));
|
||||||
|
|
||||||
|
let mut validation_info =
|
||||||
|
vk::LayerSettingsCreateInfoEXT::default().settings(desc.layer_settings);
|
||||||
|
|
||||||
|
let layers = match get_layers(&entry, desc.layers.to_vec()) {
|
||||||
|
Ok(layers) => layers,
|
||||||
|
Err((supported, unsupported)) => {
|
||||||
|
tracing::error!(
|
||||||
|
"Some requested layers were not supported by instance:\nSupported: {:?}\nUnsupported: {:?}",
|
||||||
|
supported,
|
||||||
|
unsupported
|
||||||
|
);
|
||||||
|
supported
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut requested_extensions = desc
|
||||||
|
.instance_extensions
|
||||||
|
.iter()
|
||||||
|
.map(|name| Extension { name, version: 0 })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
requested_extensions.push(make_extension!(ext::debug_utils as 1));
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
requested_extensions.push(make_extension!(ext::layer_settings));
|
||||||
|
|
||||||
|
let (extensions, unsupported_extensions) =
|
||||||
|
get_extensions(&entry, &layers, requested_extensions, desc.display_handle)?;
|
||||||
|
|
||||||
|
if !unsupported_extensions.is_empty() {
|
||||||
|
tracing::error!(
|
||||||
|
"extensions were requested but not supported by instance: {:?}",
|
||||||
|
unsupported_extensions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let layers = layers
|
||||||
|
.iter()
|
||||||
|
.map(|layer| layer.as_ptr())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let extensions = extensions
|
||||||
|
.iter()
|
||||||
|
.map(|ext| ext.name.as_ptr())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let create_info = vk::InstanceCreateInfo::default()
|
||||||
|
.application_info(&app_info)
|
||||||
|
.enabled_extension_names(&extensions)
|
||||||
|
.enabled_layer_names(&layers)
|
||||||
|
.push_next(&mut validation_info);
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"Creating instance:\napp_info: {app_info:#?}\ncreate_info: {create_info:#?}"
|
||||||
|
);
|
||||||
|
|
||||||
|
let instance = unsafe { entry.create_instance(&create_info, None)? };
|
||||||
|
|
||||||
|
let debug_utils = {
|
||||||
|
let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default()
|
||||||
|
.message_severity(
|
||||||
|
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR
|
||||||
|
| vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
|
||||||
|
| vk::DebugUtilsMessageSeverityFlagsEXT::INFO,
|
||||||
|
)
|
||||||
|
.message_type(
|
||||||
|
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
|
||||||
|
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
|
||||||
|
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
|
||||||
|
)
|
||||||
|
.pfn_user_callback(Some(crate::debug::debug_callback));
|
||||||
|
|
||||||
|
let instance = ext::debug_utils::Instance::new(&entry, &instance);
|
||||||
|
let messenger = unsafe { instance.create_debug_utils_messenger(&debug_info, None)? };
|
||||||
|
|
||||||
|
crate::DebugUtils {
|
||||||
|
instance,
|
||||||
|
messenger,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let instance = Arc::new(InstanceInner {
|
||||||
|
raw: instance,
|
||||||
|
_debug_utils: debug_utils,
|
||||||
|
entry,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self { inner: instance })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct DebugUtils {
|
||||||
|
pub instance: ext::debug_utils::Instance,
|
||||||
|
pub messenger: vk::DebugUtilsMessengerEXT,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DebugUtils {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.instance
|
||||||
|
.destroy_debug_utils_messenger(self.messenger, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -435,30 +435,8 @@ pub struct PhysicalDevice {
|
||||||
properties: PhysicalDeviceProperties,
|
properties: PhysicalDeviceProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DebugUtils {
|
pub(crate) use instance::DebugUtils;
|
||||||
instance: ext::debug_utils::Instance,
|
pub use instance::{DebugUtilsCreateInfo, Instance};
|
||||||
messenger: vk::DebugUtilsMessengerEXT,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for DebugUtils {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
self.instance
|
|
||||||
.destroy_debug_utils_messenger(self.messenger, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DebugUtilsCreateInfo {
|
|
||||||
pub severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
|
||||||
pub message_type: vk::DebugUtilsMessageTypeFlagsEXT,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Instance {
|
|
||||||
entry: Entry,
|
|
||||||
raw: ash::Instance,
|
|
||||||
_debug_utils: DebugUtils,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SamplerCache {
|
pub struct SamplerCache {
|
||||||
device: Device,
|
device: Device,
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@ use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||||
use crate::{
|
use crate::{
|
||||||
Instance, Result, define_device_owned_handle,
|
Instance, Result, define_device_owned_handle,
|
||||||
device::{Device, DeviceOwned},
|
device::{Device, DeviceOwned},
|
||||||
images, sync,
|
images,
|
||||||
|
instance::InstanceInner,
|
||||||
|
sync,
|
||||||
util::RawMutexGuard,
|
util::RawMutexGuard,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -40,7 +42,7 @@ impl Drop for Surface {
|
||||||
|
|
||||||
impl Surface {
|
impl Surface {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn headless(instance: &Arc<Instance>) -> Result<Self> {
|
pub fn headless(instance: &Arc<InstanceInner>) -> Result<Self> {
|
||||||
let headless_instance =
|
let headless_instance =
|
||||||
ash::ext::headless_surface::Instance::new(&instance.entry, &instance.raw);
|
ash::ext::headless_surface::Instance::new(&instance.entry, &instance.raw);
|
||||||
let functor = khr::surface::Instance::new(&instance.entry, &instance.raw);
|
let functor = khr::surface::Instance::new(&instance.entry, &instance.raw);
|
||||||
|
|
@ -67,7 +69,7 @@ impl Surface {
|
||||||
/// was created with the appropriate platform-specific surface extensions
|
/// was created with the appropriate platform-specific surface extensions
|
||||||
/// enabled.
|
/// enabled.
|
||||||
pub unsafe fn new_from_raw_window_handle(
|
pub unsafe fn new_from_raw_window_handle(
|
||||||
instance: &Arc<Instance>,
|
instance: &Arc<InstanceInner>,
|
||||||
display_handle: RawDisplayHandle,
|
display_handle: RawDisplayHandle,
|
||||||
window_handle: RawWindowHandle,
|
window_handle: RawWindowHandle,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
|
|
@ -704,7 +706,7 @@ impl WindowSurface {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::device;
|
use crate::make_extension;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
@ -712,14 +714,8 @@ mod tests {
|
||||||
let device = Device::new_from_default_desc(
|
let device = Device::new_from_default_desc(
|
||||||
None,
|
None,
|
||||||
&[
|
&[
|
||||||
device::Extension {
|
make_extension!(ash::ext::headless_surface),
|
||||||
name: "VK_EXT_headless_surface",
|
make_extension!(ash::khr::surface),
|
||||||
version: ash::ext::headless_surface::SPEC_VERSION,
|
|
||||||
},
|
|
||||||
device::Extension {
|
|
||||||
name: "VK_KHR_surface",
|
|
||||||
version: ash::khr::surface::SPEC_VERSION,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue