use crate::hello_triangle::memory::VulkanImageMemory; use crate::hello_triangle::surface::VulkanSurface; use crate::hello_triangle::vulkan_base::VulkanBase; use ash::prelude::VkResult; use ash::vk; use ash::vk::Extent3D; use std::sync::Arc; pub struct VulkanSwapchain { pub swapchain: vk::SwapchainKHR, pub loader: ash::khr::swapchain::Device, pub format: vk::SurfaceFormatKHR, pub extent: vk::Extent2D, pub mode: vk::PresentModeKHR, pub swapchain_images: Vec, pub swapchain_image_views: Vec, pub render_images: Vec<(vk::Image, VulkanImageMemory)>, pub render_image_views: Vec, device: Arc, } impl VulkanSwapchain { pub fn new( base: &VulkanBase, surface: &VulkanSurface, width: u32, height: u32, ) -> VkResult { let format = surface.choose_format(base)?; let mode = surface.choose_present_mode(base)?; let extent = surface.choose_swapchain_extent(base, width, height)?; let capabilities = surface.get_capabilities(base)?; let image_count = capabilities.min_image_count + 1; let image_count = if capabilities.max_image_count > 0 { image_count.min(capabilities.max_image_count) } else { image_count }; if base.graphics_queue != surface.present_queue { panic!("exclusive mode only") } let create_info = vk::SwapchainCreateInfoKHR::default() .surface(surface.surface) .present_mode(mode) .min_image_count(image_count) .image_color_space(format.color_space) .image_format(format.format) .image_extent(extent) .image_sharing_mode(vk::SharingMode::EXCLUSIVE) .pre_transform(capabilities.current_transform) .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) .clipped(true) .image_array_layers(1) // todo: switch to IMAGE_USAGE_TRANSFER_DST .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT); let loader = ash::khr::swapchain::Device::new(&base.instance, &base.device); let swapchain = unsafe { loader.create_swapchain(&create_info, None)? }; let swapchain_images = unsafe { loader.get_swapchain_images(swapchain)? }; let mut render_images = vec![]; // create render imaghes for _ in 0..swapchain_images.len() { let create_info = vk::ImageCreateInfo::default() .extent(Extent3D { width, height, depth: 1, }) .format(format.format) .image_type(vk::ImageType::TYPE_2D) .sharing_mode(vk::SharingMode::EXCLUSIVE) .samples(vk::SampleCountFlags::TYPE_1) .tiling(vk::ImageTiling::OPTIMAL) .array_layers(1) .mip_levels(1) .usage( vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::TRANSFER_SRC, ) .initial_layout(vk::ImageLayout::UNDEFINED); unsafe { let image = base.device.create_image(&create_info, None)?; let mem_reqs = base.device.get_image_memory_requirements(image); let memory = VulkanImageMemory::new(&base.device, &base.allocator, mem_reqs, &image) .unwrap(); render_images.push((image, memory)) } } let swapchain_image_views: VkResult> = swapchain_images .iter() .map(|image| { let create_info = vk::ImageViewCreateInfo::default() .view_type(vk::ImageViewType::TYPE_2D) .format(format.format) .components(vk::ComponentMapping { r: vk::ComponentSwizzle::IDENTITY, g: vk::ComponentSwizzle::IDENTITY, b: vk::ComponentSwizzle::IDENTITY, a: vk::ComponentSwizzle::IDENTITY, }) .subresource_range(vk::ImageSubresourceRange { aspect_mask: vk::ImageAspectFlags::COLOR, base_mip_level: 0, level_count: 1, base_array_layer: 0, layer_count: 1, }) .image(*image); let view = unsafe { base.device.create_image_view(&create_info, None)? }; // unsafe { // base.debug // .loader // .set_debug_utils_object_name( // base.device.handle(), // &vk::DebugUtilsObjectNameInfoEXT::default() // .object_handle(image.as_raw()) // .object_name(CStr::from_bytes_with_nul_unchecked( // b"SwapchainImage\0", // )) // .object_type(vk::ObjectType::IMAGE) // , // ) // .expect("could not set object name"); // base.debug // .loader // .set_debug_utils_object_name( // base.device.handle(), // &vk::DebugUtilsObjectNameInfoEXT::default() // .object_handle(view.as_raw()) // .object_name(CStr::from_bytes_with_nul_unchecked( // b"SwapchainImageView\0", // )) // .object_type(vk::ObjectType::IMAGE_VIEW) // , // ) // .expect("could not set object name"); // } Ok(view) }) .collect(); let render_image_views: VkResult> = render_images .iter() .map(|(image, _)| { let create_info = vk::ImageViewCreateInfo::default() .view_type(vk::ImageViewType::TYPE_2D) .format(format.format) .components(vk::ComponentMapping { r: vk::ComponentSwizzle::IDENTITY, g: vk::ComponentSwizzle::IDENTITY, b: vk::ComponentSwizzle::IDENTITY, a: vk::ComponentSwizzle::IDENTITY, }) .subresource_range(vk::ImageSubresourceRange { aspect_mask: vk::ImageAspectFlags::COLOR, base_mip_level: 0, level_count: 1, base_array_layer: 0, layer_count: 1, }) .image(*image); let view = unsafe { base.device.create_image_view(&create_info, None)? }; // unsafe { // base.debug // .loader // .set_debug_utils_object_name( // base.device.handle(), // &vk::DebugUtilsObjectNameInfoEXT::default() // .object_handle(view.as_raw()) // .object_name(CStr::from_bytes_with_nul_unchecked( // b"RenderImageView\0", // )) // .object_type(vk::ObjectType::IMAGE_VIEW) // , // ) // .expect("could not set object name"); // } Ok(view) }) .collect(); Ok(VulkanSwapchain { swapchain, loader, format, extent, mode, swapchain_images, render_images, swapchain_image_views: swapchain_image_views?, render_image_views: render_image_views?, device: base.device.clone(), }) } } impl Drop for VulkanSwapchain { fn drop(&mut self) { unsafe { for view in &self.render_image_views { self.device.destroy_image_view(*view, None) } for (view, _memory) in &self.render_images { self.device.destroy_image(*view, None); } self.loader.destroy_swapchain(self.swapchain, None) } } }