use anyhow::Result; use winit::window::Window; use vulkanalia::prelude::v1_0::*; // extension imports use vulkanalia::vk::KhrSurfaceExtension; use vulkanalia::vk::KhrSwapchainExtension; use crate::app_data; use crate::queue_family_indices; use crate::image; #[derive(Clone, Debug)] pub struct SwapchainSupport { pub capabilities: vk::SurfaceCapabilitiesKHR, pub formats: Vec<vk::SurfaceFormatKHR>, pub present_modes: Vec<vk::PresentModeKHR>, } impl SwapchainSupport { pub unsafe fn get( instance: &Instance, data: &app_data::AppData, physical_device: vk::PhysicalDevice, ) -> Result<Self> { 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)?, }) } } pub fn get_swapchain_surface_format( formats: &[vk::SurfaceFormatKHR], ) -> vk::SurfaceFormatKHR { formats .iter() .cloned() .find(|f| { f.format == vk::Format::B8G8R8A8_SRGB && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR }) .unwrap_or_else(|| formats[0]) } pub fn get_swapchain_present_mode( present_modes: &[vk::PresentModeKHR], ) -> vk::PresentModeKHR { present_modes .iter() .cloned() .find(|m| *m == vk::PresentModeKHR::MAILBOX) .unwrap_or(vk::PresentModeKHR::FIFO) } pub fn get_swapchain_extent( window: &Window, capabilities: vk::SurfaceCapabilitiesKHR, ) -> vk::Extent2D { if capabilities.current_extent.width != u32::MAX { capabilities.current_extent } else { vk::Extent2D::builder() .width(window.inner_size().width.clamp( capabilities.min_image_extent.width, capabilities.max_image_extent.width, )) .height(window.inner_size().height.clamp( capabilities.min_image_extent.height, capabilities.max_image_extent.height, )) .build() } } pub unsafe fn create_swapchain( window: &Window, instance: &Instance, device: &Device, data: &mut app_data::AppData, ) -> Result<()> { let indices = queue_family_indices::QueueFamilyIndices::get(instance, data, data.physical_device)?; let support = SwapchainSupport::get(instance, data, data.physical_device)?; let surface_format = get_swapchain_surface_format(&support.formats); let present_mode = get_swapchain_present_mode(&support.present_modes); let extent = get_swapchain_extent(window, support.capabilities); let mut image_count = support.capabilities.min_image_count + 1; if support.capabilities.max_image_count != 0 && image_count > support.capabilities.max_image_count { image_count = support.capabilities.max_image_count; } let mut queue_family_indices = vec![]; let image_sharing_mode = if indices.graphics != indices.present { queue_family_indices.push(indices.graphics); queue_family_indices.push(indices.present); vk::SharingMode::CONCURRENT } else { vk::SharingMode::EXCLUSIVE }; let info = vk::SwapchainCreateInfoKHR::builder() .surface(data.surface) .min_image_count(image_count) .image_format(surface_format.format) .image_color_space(surface_format.color_space) .image_extent(extent) .image_array_layers(1) .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) .image_sharing_mode(image_sharing_mode) .queue_family_indices(&queue_family_indices) .pre_transform(support.capabilities.current_transform) .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) .present_mode(present_mode) .clipped(true) .old_swapchain(vk::SwapchainKHR::null()); data.swapchain = device.create_swapchain_khr(&info, None)?; data.swapchain_format = surface_format.format; data.swapchain_extent = extent; data.swapchain_images = device.get_swapchain_images_khr(data.swapchain)?; Ok(()) } pub unsafe fn create_swapchain_image_views( device: &Device, data: &mut app_data::AppData, ) -> Result<()> { data.swapchain_image_views = data .swapchain_images .iter() .map(|i| image::create_image_view(device, *i, data.swapchain_format, vk::ImageAspectFlags::COLOR, 1)) .collect::<Result<Vec<_>, _>>()?; Ok(()) }