use crate::{Error, Result};
use ash::{vk, Entry, Instance};
use std::ffi::{CStr, CString};
pub const VALIDATION_LAYERS: &[&str] = &["VK_LAYER_KHRONOS_validation"];
#[cfg(debug_assertions)]
pub const ENABLE_VALIDATION_LAYERS: bool = true;
#[cfg(not(debug_assertions))]
pub const ENABLE_VALIDATION_LAYERS: bool = false;
pub const INSTANCE_EXTENSIONS: &[&str] = &["VK_EXT_debug_utils"];
pub fn get_layers() -> &'static [&'static str] {
if ENABLE_VALIDATION_LAYERS {
VALIDATION_LAYERS
} else {
&[]
}
}
pub fn create(
entry: &Entry,
extensions: &[String],
name: &str,
engine_name: &str,
) -> Result<Instance> {
let name = CString::new(name).unwrap();
let engine_name = CString::new(engine_name).unwrap();
let app_info = vk::ApplicationInfo::builder()
.application_name(&name)
.engine_name(&engine_name);
let extensions = extensions
.iter()
.cloned()
.map(CString::new)
.chain(INSTANCE_EXTENSIONS.iter().map(|s| CString::new(*s)))
.collect::<std::result::Result<Vec<_>, _>>()
.unwrap();
let missing = get_missing_extensions(entry, &extensions)?;
if !missing.is_empty() {
return Err(Error::MissingExtensions(missing));
}
let extension_names_raw = extensions
.iter()
.map(|ext| ext.as_ptr() as *const i8)
.collect::<Vec<_>>();
let instance_layers = get_layers();
let layers = instance_layers
.iter()
.map(|s| CString::new(*s))
.collect::<std::result::Result<Vec<_>, _>>()
.unwrap();
let missing = get_missing_layers(entry, &layers)?;
if !layers.is_empty() && !missing.is_empty() {
return Err(Error::MissingLayers(missing));
}
let layer_names_raw = layers
.iter()
.map(|layer| layer.as_ptr() as *const i8)
.collect::<Vec<_>>();
let create_info = vk::InstanceCreateInfo::builder()
.application_info(&app_info)
.enabled_extension_names(&extension_names_raw)
.enabled_layer_names(&layer_names_raw);
let instance = unsafe { entry.create_instance(&create_info, None)? };
Ok(instance)
}
pub fn destroy(instance: &Instance) {
unsafe { instance.destroy_instance(None) };
}
fn get_missing_extensions(entry: &Entry, extensions: &[CString]) -> Result<Vec<CString>> {
let available = entry.enumerate_instance_extension_properties()?;
Ok(extensions
.iter()
.filter(|ext| {
available.iter().all(|avail| unsafe {
CStr::from_ptr(avail.extension_name.as_ptr()) == ext.as_c_str()
})
})
.cloned()
.collect())
}
fn get_missing_layers(entry: &Entry, layers: &[CString]) -> Result<Vec<CString>> {
let available = entry.enumerate_instance_layer_properties()?;
Ok(layers
.iter()
.filter(|ext| {
available
.iter()
.all(|avail| unsafe { CStr::from_ptr(avail.layer_name.as_ptr()) == ext.as_c_str() })
})
.cloned()
.collect())
}