use anyhow::{anyhow, Result}; use log::*; use std::collections::HashSet; use std::ffi::CStr; use std::os::raw::c_void; use vulkanalia::loader::{LibloadingLoader, LIBRARY}; use vulkanalia::prelude::v1_0::*; use vulkanalia::vk::ExtDebugUtilsExtension; use vulkanalia::window as vk_window; use winit::window::Window; const VALIDATION_ENABLED: bool = cfg!(debug_assertions); const VALIDATION_LAYER: vk::ExtensionName = vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation"); extern "system" fn debug_callback( severity: vk::DebugUtilsMessageSeverityFlagsEXT, type_: vk::DebugUtilsMessageTypeFlagsEXT, data: *const vk::DebugUtilsMessengerCallbackDataEXT, _: *mut c_void, ) -> vk::Bool32 { let data = unsafe { *data }; let message = unsafe { CStr::from_ptr(data.message) }.to_string_lossy(); if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR { error!("({:?}) {}", type_, message); } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING { warn!("({:?}) {}", type_, message); } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO { debug!("({:?}) {}", type_, message); } else { trace!("({:?}) {}", type_, message); } vk::FALSE } unsafe fn create_instance(window: &Window, entry: &Entry, data: &mut AppData) -> Result { let application_info = vk::ApplicationInfo::builder() .application_name(b"Vulkan Tutorial\0") .application_version(vk::make_version(1, 0, 0)) .engine_name(b"No Engine\0") .engine_version(vk::make_version(1, 0, 0)) .api_version(vk::make_version(1, 0, 0)); let available_layers = entry .enumerate_instance_layer_properties()? .iter() .map(|l| l.layer_name) .collect::>(); if VALIDATION_ENABLED && !available_layers.contains(&VALIDATION_LAYER) { return Err(anyhow!("Validation layer requested but not supported.")); } let layers = if VALIDATION_ENABLED { vec![VALIDATION_LAYER.as_ptr()] } else { Vec::new() }; let mut extensions = vk_window::get_required_instance_extensions(window) .iter() .map(|e| e.as_ptr()) .collect::>(); if VALIDATION_ENABLED { extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION.name.as_ptr()); } // Compatibility extension for macOS let flags = if entry .enumerate_instance_extension_properties(None)? .iter() .any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name) { extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr()); vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR } else { vk::InstanceCreateFlags::empty() }; let mut info = vk::InstanceCreateInfo::builder() .application_info(&application_info) .enabled_layer_names(&layers) .enabled_extension_names(&extensions) .flags(flags); let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all()) .message_type(vk::DebugUtilsMessageTypeFlagsEXT::all()) .user_callback(Some(debug_callback)); if VALIDATION_ENABLED { info = info.push_next(&mut debug_info); } let instance = entry.create_instance(&info, None)?; Ok(instance) } /// Our Vulkan app. #[derive(Clone, Debug)] pub struct App { entry: Entry, instance: Instance, data: AppData, } impl App { /// Creates our Vulkan app. pub unsafe fn create(window: &Window) -> Result { let loader = LibloadingLoader::new(LIBRARY)?; let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?; let mut data = AppData::default(); let instance = create_instance(window, &entry, &mut data)?; Ok(Self { entry, instance, data }) } /// Renders a frame for our Vulkan app. pub unsafe fn render(&mut self, window: &Window) -> Result<()> { Ok(()) } /// Destroys our Vulkan app. pub unsafe fn destroy(&mut self) { if VALIDATION_ENABLED { self.instance.destroy_debug_utils_messenger_ext(self.data.messenger, None); } self.instance.destroy_instance(None); } } /// The Vulkan handles and associated properties used by our Vulkan app. #[derive(Clone, Debug, Default)] struct AppData { messenger: vk::DebugUtilsMessengerEXT, }