vidya/crates/renderer/src/instance.rs
2026-03-26 23:18:02 +01:00

173 lines
5.3 KiB
Rust

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);
}
}
}