use std::{any::Any, sync::Arc}; use vulkano::{ Version, VulkanLibrary, command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, allocator::StandardCommandBufferAllocator, }, descriptor_set::allocator::StandardDescriptorSetAllocator, device::{ Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags, physical::{PhysicalDevice, PhysicalDeviceType}, }, instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}, memory::allocator::StandardMemoryAllocator, swapchain::Surface, }; use winit::{ event_loop::EventLoop, raw_window_handle::{HasDisplayHandle, HasWindowHandle}, }; pub struct VulkanContext { instance: Arc, pub device: Arc, pub graphics_queue: Arc, pub memory_allocator: Arc, pub command_buffer_allocator: Arc, pub descriptor_set_allocator: Arc, } impl From<&EventLoop<()>> for VulkanContext { fn from(event_loop: &EventLoop<()>) -> Self { let library = load_library(); let enabled_extensions = Surface::required_extensions(event_loop).unwrap(); let instance = create_instance(library.clone(), enabled_extensions); let (device, mut queues) = pick_graphics_device(&instance, event_loop); let graphics_queue = queues.next().unwrap(); let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( device.clone(), Default::default(), )); let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( device.clone(), Default::default(), )); Self { instance, device, graphics_queue, memory_allocator, command_buffer_allocator, descriptor_set_allocator, } } } impl VulkanContext { pub fn create_surface( &self, window: Arc, ) -> Arc { Surface::from_window(self.instance.clone(), window).unwrap() } pub fn create_render_builder(&self) -> AutoCommandBufferBuilder { AutoCommandBufferBuilder::primary( self.command_buffer_allocator.clone(), self.graphics_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) .unwrap() } } fn load_library() -> Arc { let library = VulkanLibrary::new().unwrap(); log::debug!("Available layer:"); for layer in library.layer_properties().unwrap() { log::debug!( "\t - Layer name: {}, Description: {}, Implementation Version: {}, Vulkan Version: {}", layer.name(), layer.description(), layer.implementation_version(), layer.vulkan_version() ); } library } fn create_instance( library: Arc, required_extensions: InstanceExtensions, ) -> Arc { Instance::new( library, InstanceCreateInfo { // Enable enumerating devices that use non-conformant Vulkan implementations. // (e.g. MoltenVK) flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, enabled_extensions: required_extensions, enabled_layers: vec![String::from("VK_LAYER_KHRONOS_validation")], ..Default::default() }, ) .unwrap() } fn find_physical_device_queue_family_indexes( physical_device: &Arc, event_loop: &EventLoop<()>, ) -> Option { let mut graphic_queue_family_index = None; for (i, queue_family_property) in physical_device.queue_family_properties().iter().enumerate() { if queue_family_property .queue_flags .intersects(QueueFlags::GRAPHICS) && physical_device .presentation_support(i as u32, event_loop) .unwrap() { graphic_queue_family_index = Some(i as u32); } } graphic_queue_family_index } fn pick_physical_device_and_queue_family_indexes( instance: &Arc, event_loop: &EventLoop<()>, device_extensions: &DeviceExtensions, ) -> Option<(Arc, u32)> { instance .enumerate_physical_devices() .unwrap() .filter(|p| { p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering }) .filter(|p| p.supported_extensions().contains(device_extensions)) .filter_map(|p| { find_physical_device_queue_family_indexes(&p, event_loop) .and_then(|indexes| Some((p, indexes))) }) .min_by_key(|(p, _)| match p.properties().device_type { PhysicalDeviceType::DiscreteGpu => 0, PhysicalDeviceType::IntegratedGpu => 1, PhysicalDeviceType::VirtualGpu => 2, PhysicalDeviceType::Cpu => 3, PhysicalDeviceType::Other => 4, _ => 5, }) } fn pick_graphics_device( instance: &Arc, event_loop: &EventLoop<()>, ) -> ( Arc, impl ExactSizeIterator> + use<>, ) { let mut device_extensions = DeviceExtensions { khr_swapchain: true, ..DeviceExtensions::empty() }; let (physical_device, graphics_family_index) = pick_physical_device_and_queue_family_indexes(instance, event_loop, &device_extensions) .unwrap(); log::debug!( "Using device: {} (type: {:?})", physical_device.properties().device_name, physical_device.properties().device_type, ); if physical_device.api_version() < Version::V1_3 { device_extensions.khr_dynamic_rendering = true; } log::debug!("Using device extensions: {:#?}", device_extensions); Device::new( physical_device, DeviceCreateInfo { queue_create_infos: vec![QueueCreateInfo { queue_family_index: graphics_family_index, ..Default::default() }], enabled_extensions: device_extensions, enabled_features: DeviceFeatures { dynamic_rendering: true, ..DeviceFeatures::empty() }, ..Default::default() }, ) .unwrap() }