mod functions; use functions::{ create_instance, create_logical_device, create_pipeline, create_render_pass, create_swapchain, create_swapchain_image_views, pick_physical_device, }; use crate::VALIDATION_ENABLED; use ::anyhow::{anyhow, Result}; use ::log::*; use ::thiserror::Error; use ::vulkanalia::loader::{LibloadingLoader, LIBRARY}; use ::vulkanalia::prelude::v1_0::*; use ::vulkanalia::vk::{ExtDebugUtilsExtension, KhrSurfaceExtension, KhrSwapchainExtension}; use ::vulkanalia::window as vk_window; use ::winit::window::Window; pub(crate) const VALIDATION_LAYER: vk::ExtensionName = vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation"); pub(crate) const DEVICE_EXTENSIONS: &[vk::ExtensionName] = &[vk::KHR_SWAPCHAIN_EXTENSION.name]; /// Our Vulkan app. #[derive(Clone, Debug)] pub struct App { entry: Entry, instance: Instance, data: AppData, device: Device, } 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)?; data.surface = vk_window::create_surface(&instance, window)?; pick_physical_device(&instance, &mut data)?; let device = create_logical_device(&instance, &mut data)?; create_swapchain(window, &instance, &device, &mut data)?; create_swapchain_image_views(&device, &mut data)?; create_render_pass(&instance, &device, &mut data)?; create_pipeline(&device, &mut data)?; Ok(Self { entry, instance, data, device, }) } /// 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) { self.device .destroy_pipeline_layout(self.data.pipeline_layout, None); self.device.destroy_render_pass(self.data.render_pass, None); self.data .swapchain_image_views .iter() .for_each(|v| self.device.destroy_image_view(*v, None)); self.device.destroy_swapchain_khr(self.data.swapchain, None); self.device.destroy_device(None); self.instance.destroy_surface_khr(self.data.surface, None); 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)] pub struct AppData { // Debug messenger: vk::DebugUtilsMessengerEXT, // Surface surface: vk::SurfaceKHR, // Physical Device / Logical Device physical_device: vk::PhysicalDevice, graphics_queue: vk::Queue, present_queue: vk::Queue, // Swapchain swapchain_format: vk::Format, swapchain_extent: vk::Extent2D, swapchain: vk::SwapchainKHR, swapchain_images: Vec, swapchain_image_views: Vec, render_pass: vk::RenderPass, pipeline_layout: vk::PipelineLayout, } impl AppData {} #[derive(Debug, Error)] #[error("Missing {0}.")] pub struct SuitabilityError(pub &'static str); #[derive(Copy, Clone, Debug)] pub(crate) struct QueueFamilyIndices { graphics: u32, present: u32, } impl QueueFamilyIndices { unsafe fn get( instance: &Instance, data: &AppData, physical_device: vk::PhysicalDevice, ) -> Result { let properties = instance.get_physical_device_queue_family_properties(physical_device); let graphics = properties .iter() .position(|p| p.queue_flags.contains(vk::QueueFlags::GRAPHICS)) .map(|i| i as u32); let mut present = None; for (index, _properties) in properties.iter().enumerate() { if instance.get_physical_device_surface_support_khr( physical_device, index as u32, data.surface, )? { present = Some(index as u32); break; } } if let (Some(graphics), Some(present)) = (graphics, present) { Ok(Self { graphics, present }) } else { Err(anyhow!(SuitabilityError( "Missing required queue families." ))) } } } #[derive(Clone, Debug)] pub(crate) struct SwapchainSupport { capabilities: vk::SurfaceCapabilitiesKHR, formats: Vec, present_modes: Vec, } impl SwapchainSupport { unsafe fn get( instance: &Instance, data: &AppData, physical_device: vk::PhysicalDevice, ) -> Result { Ok(Self { capabilities: instance .get_physical_device_surface_capabilities_khr(physical_device, data.surface)?, formats: instance .get_physical_device_surface_formats_khr(physical_device, data.surface)?, present_modes: instance .get_physical_device_surface_present_modes_khr(physical_device, data.surface)?, }) } }