rust_vulkan_test/src/vulkan/vk_instance.rs
2024-11-12 13:25:52 +01:00

166 lines
No EOL
5.2 KiB
Rust

use crate::vulkan::utils::formatter::format_instance_layer;
use crate::vulkan::utils::layers::{use_layers, LayersSelector};
use crate::vulkan::vk_surface::VkSurface;
use crate::vulkan::{VkPhysicalDevice, LOG_TARGET};
use ash::khr::surface;
use ash::prelude::VkResult;
use ash::vk::QueueFlags;
use ash::{vk, Entry, Instance};
use std::ffi::{c_char, CStr, CString};
use std::fmt::{Display, Formatter};
use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
pub struct VkInstance {
entry: Entry,
handle: Instance,
}
impl VkInstance {
pub fn new(
required_extensions: &Vec<*const c_char>,
) -> Self {
let entry = Entry::linked();
log::debug!(target: LOG_TARGET, "Initializing Vulkan instance");
{
let required_extensions = required_extensions
.iter()
.map(|str| unsafe { CStr::from_ptr(*str) })
.map(|cstr| cstr.to_string_lossy())
.collect::<Vec<_>>();
log::debug!(target: LOG_TARGET, "Required instance extensions: {}", required_extensions.join(", "));
}
// Layers
let layers = use_layers(
&entry,
LayersSelector::SpecificLayers(vec![
"VK_LAYER_KHRONOS_validation",
"VK_LAYER_MANGOHUD_overlay_x86_64",
"VK_LAYER_NV_optimus"
]),
);
{
let layers = layers.iter()
.map(|layer| layer.to_string_lossy())
.collect::<Vec<_>>();
log::debug!(target: LOG_TARGET, "Selected debug layers : {}", layers.join(", "))
}
let layers_raw = layers.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
// App Info
let app_name = CString::new("VulkanTriangle").unwrap();
let appinfo = vk::ApplicationInfo::default()
.application_name(app_name.as_c_str())
.application_version(0)
.engine_name(app_name.as_c_str())
.engine_version(0)
.api_version(vk::make_api_version(0, 1, 0, 0));
let create_flags = if cfg!(any(target_os = "macos", target_os = "ios")) {
vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
} else {
vk::InstanceCreateFlags::default()
};
// Instance Info
let create_info = vk::InstanceCreateInfo::default()
.application_info(&appinfo)
.enabled_layer_names(&layers_raw)
.enabled_extension_names(&required_extensions)
.flags(create_flags);
let instance: Instance = unsafe {
entry
.create_instance(&create_info, None)
.expect("Instance creation error")
};
log::debug!(target: LOG_TARGET, "Vulkan instance created");
Self {
entry,
handle: instance,
}
}
pub fn get_physical_devices(&self) -> Vec<VkPhysicalDevice> {
let physical_devices = unsafe { self.handle.enumerate_physical_devices() };
physical_devices
.unwrap_or_default()
.iter().map(|physical_device| VkPhysicalDevice::new(&self.handle, *physical_device))
.collect()
}
pub fn create_surface(
&self,
window: &crate::display::Window,
) -> anyhow::Result<VkSurface> {
let window_handle = window.handle()
.ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?;
let surface_loader = surface::Instance::new(&self.entry, &self.handle);
let surface = unsafe {
ash_window::create_surface(
&self.entry,
&self.handle,
window_handle.display_handle()?.as_raw(),
window_handle.window_handle()?.as_raw(),
None,
)?
};
log::debug!(target: LOG_TARGET, "Surface created");
Ok(VkSurface::new(
surface_loader,
surface,
))
}
pub fn create_device(
&self,
physical_device: &VkPhysicalDevice,
create_info: &vk::DeviceCreateInfo,
allocation_callbacks: Option<&vk::AllocationCallbacks>,
) -> VkResult<ash::Device> {
unsafe {
self.handle.create_device(physical_device.handle, &create_info, allocation_callbacks)
}
}
}
impl Drop for VkInstance {
fn drop(&mut self) {
unsafe {
self.handle.destroy_instance(None);
}
log::debug!(target: LOG_TARGET, "Vulkan instance destroyed");
}
}
impl Display for VkInstance {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "")?;
let instance_layers = unsafe { self.entry.enumerate_instance_layer_properties().unwrap_or_default() };
writeln!(f, "Instance layers ({}) :", instance_layers.len())?;
for instance_layer in &instance_layers {
writeln!(f, "{}", format_instance_layer(instance_layer))?;
}
writeln!(f, "")?;
let physical_devices = self.get_physical_devices();
writeln!(f, "Physical Devices ({}) :", physical_devices.len())?;
for physical_device in physical_devices {
writeln!(f, "{physical_device}")?;
}
writeln!(f, "")?;
Ok(())
}
}