use super::*; use crate::{VALIDATION_ENABLED, VALIDATION_LAYER}; use ::anyhow::{anyhow, Result}; use ::log::*; use ::std::collections::HashSet; use ::std::ffi::CStr; use ::std::os::raw::c_void; use ::vulkanalia::prelude::v1_0::*; use ::vulkanalia::window as vk_window; use ::winit::window::Window; 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 } pub(super) unsafe fn create_instance( window: &Window, entry: &Entry, data: &mut AppData, ) -> Result { // Application Info 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)); // Layers 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() }; // Extensions 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()); extensions.push( vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION .name .as_ptr(), ); vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR } else { vk::InstanceCreateFlags::empty() }; // Create 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)?; // Messenger if VALIDATION_ENABLED { data.messenger = instance.create_debug_utils_messenger_ext(&debug_info, None)?; } Ok(instance) } pub(super) unsafe fn pick_physical_device(instance: &Instance, data: &mut AppData) -> Result<()> { for physical_device in instance.enumerate_physical_devices()? { let properties = instance.get_physical_device_properties(physical_device); if let Err(error) = check_physical_device(instance, data, physical_device) { warn!( "Skipping physical device (`{}`): {}", properties.device_name, error ); } else { info!("Selected physical device (`{}`).", properties.device_name); data.physical_device = physical_device; return Ok(()); } } Err(anyhow!("Failed to find suitable physical device.")) } pub(super) unsafe fn check_physical_device( instance: &Instance, data: &AppData, physical_device: vk::PhysicalDevice, ) -> Result<()> { QueueFamilyIndicies::get(instance, data, physical_device)?; Ok(()) } pub(super) unsafe fn create_logical_device( instance: &Instance, data: &mut AppData, ) -> Result { // Queue Create Infos let indices = QueueFamilyIndicies::get(instance, data, data.physical_device)?; let mut unique_indices = HashSet::new(); unique_indices.insert(indices.graphics); unique_indices.insert(indices.present); let queue_priorities = &[1.0]; let queue_infos = unique_indices .iter() .map(|i| { vk::DeviceQueueCreateInfo::builder() .queue_family_index(*i) .queue_priorities(queue_priorities) }) .collect::>(); // Layers let layers = if VALIDATION_ENABLED { vec![VALIDATION_LAYER.as_ptr()] } else { vec![] }; // Extensions let extension_names = if instance .enumerate_device_extension_properties(data.physical_device, None)? .iter() .any(|e| e.extension_name == vk::KHR_PORTABILITY_SUBSET_EXTENSION.name) { vec![vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr()] } else { vec![] }; // Features let features = vk::PhysicalDeviceFeatures::builder(); // Create let info = vk::DeviceCreateInfo::builder() .queue_create_infos(&queue_infos) .enabled_layer_names(&layers) .enabled_features(&features) .enabled_extension_names(&extension_names); let device = instance.create_device(data.physical_device, &info, None)?; // Queues data.graphics_queue = device.get_device_queue(indices.graphics, 0); data.present_queue = device.get_device_queue(indices.present, 0); Ok(device) }