Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 0s
278 lines
9.6 KiB
Rust
278 lines
9.6 KiB
Rust
use crate::display::Window;
|
|
use crate::vulkan::vk_framebuffer::VkSwapchainFramebuffer;
|
|
use crate::vulkan::vk_render_pass::VkRenderPass;
|
|
use crate::vulkan::vk_semaphore::VkSemaphore;
|
|
use crate::vulkan::vk_surface::SwapchainSupportDetails;
|
|
use crate::vulkan::{VkDevice, VkPhysicalDevice, VkSurface};
|
|
use ash::prelude::VkResult;
|
|
use ash::vk;
|
|
use std::sync::Arc;
|
|
|
|
pub struct VkSwapchain {
|
|
surface: Arc<VkSurface>,
|
|
device: Arc<VkDevice>,
|
|
|
|
swapchain: Option<vk::SwapchainKHR>,
|
|
swapchain_support_details: SwapchainSupportDetails,
|
|
|
|
pub(super) desired_image_count: u32,
|
|
pub(super) surface_format: vk::SurfaceFormatKHR,
|
|
pub(super) surface_resolution: vk::Extent2D,
|
|
pub(super) present_mode: vk::PresentModeKHR,
|
|
pub(super) pre_transform: vk::SurfaceTransformFlagsKHR,
|
|
|
|
pub(super) present_images: Option<Vec<vk::Image>>,
|
|
pub(super) present_image_views: Option<Vec<vk::ImageView>>,
|
|
}
|
|
|
|
impl VkSwapchain {
|
|
pub(super) fn new(
|
|
window: &Window,
|
|
surface: Arc<VkSurface>,
|
|
device: Arc<VkDevice>,
|
|
physical_device: &VkPhysicalDevice,
|
|
) -> anyhow::Result<Self> {
|
|
log::debug!("Creating swapchain");
|
|
|
|
let window_size = window
|
|
.physical_size::<u32>()
|
|
.and_then(|size| {
|
|
Some(vk::Extent2D {
|
|
width: size.width,
|
|
height: size.height,
|
|
})
|
|
})
|
|
.ok_or_else(|| anyhow::anyhow!("Failed to get swapchain extent"))?;
|
|
log::debug!("Window size ({}x{})", window_size.width, window_size.height);
|
|
|
|
let swapchain_support_details =
|
|
surface.get_physical_device_swapchain_support_details(physical_device)?;
|
|
let SwapchainSupportDetails(surface_formats, surface_capabilities, present_modes) =
|
|
&swapchain_support_details;
|
|
log::debug!("Supported surface formats by physical device: {surface_formats:#?}");
|
|
log::debug!("Surface capabilities: {surface_capabilities:#?}");
|
|
log::debug!("Present modes: {present_modes:#?}");
|
|
|
|
let surface_format = Self::choose_surface_format(surface_formats)
|
|
.ok_or_else(|| anyhow::anyhow!("No available surface formats"))?;
|
|
let desired_image_count = Self::choose_desired_image_count(surface_capabilities);
|
|
let swapchain_extent = Self::choose_swapchain_extent(window_size, surface_capabilities);
|
|
let pre_transform = Self::choose_pre_transform(surface_capabilities);
|
|
let present_mode = Self::choose_present_mode(present_modes);
|
|
|
|
let mut swapchain = Self {
|
|
surface,
|
|
device,
|
|
|
|
swapchain: None,
|
|
swapchain_support_details,
|
|
desired_image_count,
|
|
surface_format,
|
|
surface_resolution: swapchain_extent,
|
|
present_mode,
|
|
pre_transform,
|
|
present_images: None,
|
|
present_image_views: None,
|
|
};
|
|
|
|
swapchain.create_swapchain()?;
|
|
|
|
Ok(swapchain)
|
|
}
|
|
|
|
pub(super) fn create_swapchain(&mut self) -> VkResult<()> {
|
|
let mut swapchain_create_info = self.create_swapchain_info(&self.surface);
|
|
|
|
if let Some(old_swapchain) = self.swapchain {
|
|
swapchain_create_info.old_swapchain = old_swapchain;
|
|
}
|
|
|
|
let swapchain = unsafe {
|
|
self.device
|
|
.swapchain_loader
|
|
.create_swapchain(&swapchain_create_info, None)?
|
|
};
|
|
|
|
let present_images = unsafe {
|
|
self.device
|
|
.swapchain_loader
|
|
.get_swapchain_images(swapchain)?
|
|
};
|
|
let present_images_view = present_images
|
|
.iter()
|
|
.map(|i| {
|
|
self.create_present_image_view(*i)
|
|
.expect("Failed to create image view")
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
if log::log_enabled!(log::Level::Debug) {
|
|
let label = match self.swapchain {
|
|
None => "Swapchain created",
|
|
Some(_) => "Swapchain updated",
|
|
};
|
|
log::debug!("{label} ({swapchain:?}) : {swapchain_create_info:#?}");
|
|
}
|
|
|
|
self.swapchain = Some(swapchain);
|
|
self.present_image_views = Some(present_images_view);
|
|
self.present_images = Some(present_images);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(super) fn create_framebuffers(&self, render_pass: Arc<VkRenderPass>) -> Option<Vec<VkSwapchainFramebuffer>> {
|
|
let present_image_views = self.present_image_views.as_ref()?;
|
|
|
|
present_image_views.iter().enumerate()
|
|
.map(|present_image_view| {
|
|
VkSwapchainFramebuffer::new()
|
|
})
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
pub(super) fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> {
|
|
log::debug!("New resolution requested ({width}x{height})");
|
|
|
|
let chosen_extent = Self::choose_swapchain_extent(
|
|
vk::Extent2D { width, height },
|
|
&self.swapchain_support_details.1,
|
|
);
|
|
if chosen_extent.width != self.surface_resolution.width
|
|
|| chosen_extent.height != self.surface_resolution.height
|
|
{
|
|
self.surface_resolution = chosen_extent;
|
|
log::debug!(
|
|
"New resolution applied ({}x{})",
|
|
chosen_extent.width,
|
|
chosen_extent.height
|
|
);
|
|
|
|
self.create_swapchain()?;
|
|
} else {
|
|
log::debug!("New resolution skipped ({width}x{height}) : Same resolution");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(super) fn acquire_next_image(&self, semaphore: &VkSemaphore) -> VkResult<(u32, bool)> {
|
|
unsafe {
|
|
self.device.swapchain_loader.acquire_next_image(
|
|
self.swapchain.unwrap(),
|
|
u64::MAX,
|
|
semaphore.handle,
|
|
vk::Fence::null(),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn create_swapchain_info(&self, surface: &VkSurface) -> vk::SwapchainCreateInfoKHR {
|
|
vk::SwapchainCreateInfoKHR::default()
|
|
.surface(surface.surface)
|
|
.min_image_count(self.desired_image_count)
|
|
.image_color_space(self.surface_format.color_space)
|
|
.image_format(self.surface_format.format)
|
|
.image_extent(self.surface_resolution)
|
|
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
|
|
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
|
|
.pre_transform(self.pre_transform)
|
|
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
|
|
.present_mode(self.present_mode)
|
|
.clipped(true)
|
|
.image_array_layers(1)
|
|
}
|
|
|
|
fn choose_swapchain_extent(
|
|
window_size: vk::Extent2D,
|
|
surface_capabilities: &vk::SurfaceCapabilitiesKHR,
|
|
) -> vk::Extent2D {
|
|
vk::Extent2D {
|
|
width: window_size
|
|
.width
|
|
.max(surface_capabilities.min_image_extent.width)
|
|
.min(surface_capabilities.max_image_extent.width),
|
|
height: window_size
|
|
.height
|
|
.max(surface_capabilities.min_image_extent.height)
|
|
.min(surface_capabilities.max_image_extent.height),
|
|
}
|
|
}
|
|
|
|
fn choose_surface_format(
|
|
surface_formats: &Vec<vk::SurfaceFormatKHR>,
|
|
) -> Option<vk::SurfaceFormatKHR> {
|
|
surface_formats.first().and_then(|f| Some(*f))
|
|
}
|
|
|
|
fn choose_desired_image_count(surface_capabilities: &vk::SurfaceCapabilitiesKHR) -> u32 {
|
|
let mut desired_image_count = surface_capabilities.min_image_count + 1;
|
|
if surface_capabilities.max_image_count > 0
|
|
&& desired_image_count > surface_capabilities.max_image_count
|
|
{
|
|
desired_image_count = surface_capabilities.max_image_count;
|
|
}
|
|
desired_image_count
|
|
}
|
|
|
|
fn choose_pre_transform(
|
|
surface_capabilities: &vk::SurfaceCapabilitiesKHR,
|
|
) -> vk::SurfaceTransformFlagsKHR {
|
|
if surface_capabilities
|
|
.supported_transforms
|
|
.contains(vk::SurfaceTransformFlagsKHR::IDENTITY)
|
|
{
|
|
vk::SurfaceTransformFlagsKHR::IDENTITY
|
|
} else {
|
|
surface_capabilities.current_transform
|
|
}
|
|
}
|
|
|
|
fn choose_present_mode(present_modes: &Vec<vk::PresentModeKHR>) -> vk::PresentModeKHR {
|
|
present_modes
|
|
.iter()
|
|
.cloned()
|
|
.find(|&mode| mode == vk::PresentModeKHR::MAILBOX)
|
|
.unwrap_or(vk::PresentModeKHR::FIFO)
|
|
}
|
|
|
|
fn create_present_image_view(&self, image: vk::Image) -> VkResult<vk::ImageView> {
|
|
let create_view_info = vk::ImageViewCreateInfo::default()
|
|
.view_type(vk::ImageViewType::TYPE_2D)
|
|
.format(self.surface_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);
|
|
|
|
unsafe {
|
|
self.device
|
|
.handle
|
|
.create_image_view(&create_view_info, None)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for VkSwapchain {
|
|
fn drop(&mut self) {
|
|
if let Some(swapchain) = self.swapchain {
|
|
unsafe {
|
|
self.device
|
|
.swapchain_loader
|
|
.destroy_swapchain(swapchain, None);
|
|
}
|
|
self.swapchain = None;
|
|
log::debug!("Swapchain destroyed ({swapchain:?})");
|
|
}
|
|
}
|
|
}
|