use std::sync::Arc;
use ash::khr::swapchain;
use ash::vk;
use ash::vk::{CompositeAlphaFlagsKHR, ImageUsageFlags, PresentModeKHR, SharingMode, SurfaceFormatKHR, SwapchainKHR};
use log::{debug, info};
use crate::graphics::renderer::WindowState;
use crate::vulkan;
use crate::vulkan::{Device, Image, Instance, Surface, LOG_TARGET};
use crate::vulkan::device::DeviceInner;
pub struct SwapchainInner {
#[allow(dead_code)]
device_dep: Arc<DeviceInner>,
swapchain_loader: swapchain::Device,
swapchain: vk::SwapchainKHR,
images: Vec<vulkan::Image>,
extent: vk::Extent2D,
format: SurfaceFormatKHR
}
impl Drop for SwapchainInner {
fn drop(&mut self) {
unsafe {
self.swapchain_loader.destroy_swapchain(self.swapchain, None)
}
}
}
pub struct Swapchain {
pub inner: Arc<SwapchainInner>,
}
impl Swapchain {
pub fn new(
instance: &Instance,
physical_device: &vk::PhysicalDevice,
device: &Device,
window: &WindowState,
surface: &Surface,
preferred_present_mode: PresentModeKHR,
old_swapchain: Option<SwapchainKHR>
) -> Swapchain {
let swapchain_loader = swapchain::Device::new(instance.handle(), device.handle());
let available_formats = surface.get_formats(physical_device);
let surface_format = available_formats.iter()
.find(|f| {
#[cfg(any(target_os = "linux", target_os = "windows"))]
let preferred_format = &&vk::SurfaceFormatKHR {
format: vk::Format::R8G8B8A8_SRGB,
color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR,
};
#[cfg(target_os = "macos")]
let preferred_format = &&vk::SurfaceFormatKHR {
format: vk::Format::B8G8R8A8_SRGB,
color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR,
};
f == preferred_format
})
.unwrap_or(available_formats.first().expect("No surface format found"));
info!(target: LOG_TARGET, "Using swapchain surface format: {:?}", surface_format);
let surface_capabilities = surface.get_surface_capabilities(physical_device);
let mut desired_image_count = surface_capabilities.min_image_count + 0;
if surface_capabilities.max_image_count > 0 && desired_image_count > surface_capabilities.max_image_count {
desired_image_count = surface_capabilities.max_image_count;
}
let pre_transform = if surface_capabilities.supported_transforms.contains(vk::SurfaceTransformFlagsKHR::IDENTITY) {
vk::SurfaceTransformFlagsKHR::IDENTITY
} else {
surface_capabilities.current_transform
};
let present_modes = surface.get_present_modes(physical_device);
let present_mode = present_modes
.iter()
.cloned()
.find(|&mode| mode == preferred_present_mode)
.unwrap_or(vk::PresentModeKHR::FIFO);
debug!(target: LOG_TARGET, "Present mode: {:?}", present_mode);
let extent = match surface_capabilities.current_extent.width {
u32::MAX => window.extent2d,
_ => surface_capabilities.current_extent
};
info!(target: LOG_TARGET, "Using swapchain extent: {:?}", extent);
info!(target: LOG_TARGET, "Using scale factor: {:?}", window.scale_factor);
info!(target: LOG_TARGET, "Using image count: {:?}", desired_image_count);
let mut create_info = vk::SwapchainCreateInfoKHR::default()
.image_usage(ImageUsageFlags::COLOR_ATTACHMENT | ImageUsageFlags::TRANSFER_DST)
.image_extent(extent)
.image_sharing_mode(SharingMode::EXCLUSIVE)
.image_format(surface_format.format)
.image_color_space(surface_format.color_space)
.composite_alpha(CompositeAlphaFlagsKHR::OPAQUE)
.pre_transform(pre_transform)
.present_mode(present_mode)
.min_image_count(desired_image_count)
.surface(*surface.handle())
.clipped(true)
.image_array_layers(1);
if let Some(old_swapchain) = old_swapchain {
create_info = create_info.old_swapchain(old_swapchain);
}
let swapchain = unsafe { swapchain_loader.create_swapchain(&create_info, None).unwrap() };
let images = unsafe { swapchain_loader.get_swapchain_images(swapchain).unwrap() }.iter()
.map(|&image| vulkan::Image::from_raw(device, image, surface_format.format, extent))
.collect::<Vec<vulkan::Image>>();
let swapchain_inner = SwapchainInner {
device_dep: device.inner.clone(),
swapchain_loader,
swapchain,
images,
extent,
format: *surface_format
};
Self {
inner: Arc::new(swapchain_inner)
}
}
pub fn get_images(&self) -> &Vec<Image> {
&self.inner.images
}
pub fn get_image_views(&self) -> Vec<vk::ImageView> {
self.inner.images.iter().map(|i| i.image_view()).collect()
}
pub fn get_image_count(&self) -> u32 {
self.inner.images.len() as u32
}
pub fn get_extent(&self) -> vk::Extent2D {
self.inner.extent
}
pub fn get_format(&self) -> SurfaceFormatKHR {
self.inner.format
}
pub fn handle(&self) -> SwapchainKHR {
self.inner.swapchain
}
pub fn queue_present(&self, queue: vk::Queue, wait_semaphore: vk::Semaphore, image_index: u32) {
let mut result = [vk::Result::SUCCESS];
unsafe {
let swapchains = [self.handle()];
let indices = [image_index];
let semaphores = [wait_semaphore];
let present_info = vk::PresentInfoKHR::default()
.wait_semaphores(&semaphores)
.swapchains(&swapchains)
.image_indices(&indices)
.results(&mut result);
self.inner.swapchain_loader.queue_present(queue, &present_info)
.expect("Failed to present queue");
}
}
pub fn acquire_next_image(&self, semaphore: vk::Semaphore) -> u32 {
unsafe {
let (image_index, _) = self.inner.swapchain_loader
.acquire_next_image(
self.handle(),
u64::MAX,
semaphore,
vk::Fence::null()
)
.expect("Failed to acquire next image");
image_index
}
}
}