vulkan_lib/vulkan-rs/src/swapchain.rs
2024-03-28 21:30:06 +01:00

335 lines
8.9 KiB
Rust

use crate::prelude::*;
use anyhow::Result;
use std::cmp;
use std::sync::Mutex;
pub enum NextImageSynchronization<'a> {
Semaphore(&'a Semaphore<'a>),
Fence(&'a Fence<'a>),
}
impl<'a> From<&'a Semaphore<'a>> for NextImageSynchronization<'a> {
fn from(value: &'a Semaphore<'a>) -> Self {
Self::Semaphore(value)
}
}
impl<'a> From<&'a Fence<'a>> for NextImageSynchronization<'a> {
fn from(value: &'a Fence<'a>) -> Self {
Self::Fence(value)
}
}
#[derive(Debug)]
pub struct Swapchain<'a> {
width: u32,
height: u32,
index: u32,
device: &'a Device,
surface: Surface<'a>,
create_info: VkSwapchainCreateInfoKHR,
swapchain: VkSwapchainKHR,
usage: VkImageUsageFlagBits,
raw: bool,
}
impl<'a> Swapchain<'a> {
pub fn new(
device: &'a Device,
surface: Surface<'a>,
vsync: bool,
image_count: u32,
image_usage: impl Into<VkImageUsageFlagBits>,
prefered_format: VkFormat,
array_layers: u32,
) -> Result<Swapchain<'a>> {
let surface_caps = surface.capabilities(&device)?;
let extent = if surface_caps.currentExtent.width == u32::max_value() {
return Err(anyhow::Error::msg("Surface has no extent"));
} else {
VkExtent2D {
width: surface_caps.currentExtent.width,
height: surface_caps.currentExtent.height,
}
};
let mut present_mode = VK_PRESENT_MODE_FIFO_KHR;
if !vsync {
for present_mode_iter in surface.present_modes(&device)? {
if present_mode_iter == VK_PRESENT_MODE_MAILBOX_KHR {
present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
} else if present_mode_iter == VK_PRESENT_MODE_IMMEDIATE_KHR {
present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
}
let swapchain_image_count = if surface_caps.maxImageCount < surface_caps.minImageCount {
cmp::max(image_count, surface_caps.minImageCount)
} else {
cmp::max(
cmp::min(image_count, surface_caps.maxImageCount),
surface_caps.minImageCount,
)
};
let pretransform =
if (surface_caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0 {
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR.into()
} else {
surface_caps.currentTransform
};
let (format, colorspace) = surface.format_colorspace(&device, prefered_format)?;
let swapchain_ci = VkSwapchainCreateInfoKHR::new(
0,
surface.vk_handle(),
swapchain_image_count,
format,
colorspace,
extent,
array_layers,
image_usage,
VK_SHARING_MODE_EXCLUSIVE,
&[],
pretransform,
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
present_mode,
device.physical_device().features().shaderClipDistance,
);
let swapchain = device.create_swapchain(&swapchain_ci)?;
Ok(Swapchain {
width: extent.width,
height: extent.height,
usage: swapchain_ci.imageUsage,
index: 0,
device,
surface,
create_info: swapchain_ci,
swapchain,
raw: false,
})
}
pub fn from_ci(device: &'a Device, swapchain_ci: &VkSwapchainCreateInfoKHR) -> Result<Self> {
Ok(Swapchain {
width: swapchain_ci.imageExtent.width,
height: swapchain_ci.imageExtent.height,
usage: swapchain_ci.imageUsage,
index: 0,
surface: Surface::from_vk_surface(
swapchain_ci.surface,
device.physical_device().instance(),
),
create_info: swapchain_ci.clone(),
swapchain: device.create_swapchain(swapchain_ci)?,
device,
raw: false,
})
}
pub fn from_raw(
device: &'a Device,
swapchain_ci: &VkSwapchainCreateInfoKHR,
swapchain: VkSwapchainKHR,
) -> Self {
Swapchain {
width: swapchain_ci.imageExtent.width,
height: swapchain_ci.imageExtent.height,
usage: swapchain_ci.imageUsage,
index: 0,
surface: Surface::from_vk_surface(
swapchain_ci.surface,
device.physical_device().instance(),
),
device,
create_info: swapchain_ci.clone(),
swapchain,
raw: true,
}
}
pub fn recreate(&mut self) -> Result<()> {
// wait for the device to get idle
self.device.wait_idle()?;
let surface_caps = self.surface.capabilities(self.device)?;
let extent = if surface_caps.currentExtent.width == u32::max_value()
|| surface_caps.currentExtent.height == u32::max_value()
{
return Err(anyhow::Error::msg("Surface has no extent"));
} else if surface_caps.currentExtent.width == 0 || surface_caps.currentExtent.height == 0 {
// don't recreate swapchain
return Ok(());
} else {
VkExtent2D {
width: surface_caps.currentExtent.width,
height: surface_caps.currentExtent.height,
}
};
let mut swapchain_ci = self.create_info.clone();
swapchain_ci.imageExtent = extent;
swapchain_ci.set_old_swapchain(self.swapchain);
let swapchain = self.device.create_swapchain(&swapchain_ci)?;
// destroy the old swapchain
self.destroy();
// replace swapchain
self.swapchain = swapchain;
// set new surface size
self.width = extent.width;
self.height = extent.height;
Ok(())
}
pub fn acquire_next_image<'b>(
&mut self,
time_out: u64,
synchro: impl Into<NextImageSynchronization<'b>>,
) -> Result<OutOfDate<u32>> {
let synchro = synchro.into();
let res = self.device.acquire_next_image(
self.swapchain,
time_out,
match synchro {
NextImageSynchronization::Semaphore(semaphore) => Some(semaphore.vk_handle()),
NextImageSynchronization::Fence(_) => None,
},
match synchro {
NextImageSynchronization::Semaphore(_) => None,
NextImageSynchronization::Fence(fence) => Some(fence.vk_handle()),
},
);
if let Ok(r) = &res {
if let OutOfDate::Ok(i) = r {
self.index = *i;
}
}
res
}
/// set current
/// only use when externally acquired next index !!!
pub unsafe fn set_image_index(&mut self, index: u32) {
self.index = index;
}
pub fn current_index(&self) -> u32 {
self.index
}
pub fn vk_images(&self) -> Result<Vec<VkImage>> {
self.device.swapchain_images(self.swapchain)
}
pub fn wrap_images(
&self,
images: &[VkImage],
queue: &'a Mutex<Queue<'a>>,
assume_layout: bool,
) -> Result<Vec<Image<'a>>> {
let format = self.format();
let tiling = VK_IMAGE_TILING_OPTIMAL;
if !Image::check_configuration(&self.device, tiling, format, self.usage) {
return Err(anyhow::Error::msg(format!(
"Image configuration not allowed (tiling: {:?}, format: {:?}, usage: {:?})",
tiling, format, self.usage,
)));
}
let mut swapchain_images = Vec::new();
for image in images {
swapchain_images.push(
Image::from_preinitialized(
*image,
format,
self.width(),
self.height(),
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
self.usage,
assume_layout,
)
.attach_sampler(Sampler::nearest_sampler().build(self.device)?)
.build(&self.device, queue)?,
);
}
Ok(swapchain_images)
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn format(&self) -> VkFormat {
self.create_info.imageFormat
}
#[inline]
fn destroy(&self) {
self.device.destroy_swapchain(self.swapchain)
}
}
impl<'a> VulkanDevice for Swapchain<'a> {
fn device(&self) -> &Device {
&self.device
}
}
impl<'a> VkHandle<VkSwapchainKHR> for Swapchain<'a> {
fn vk_handle(&self) -> VkSwapchainKHR {
self.swapchain
}
}
impl<'a> VkHandle<VkSwapchainKHR> for &'a Swapchain<'a> {
fn vk_handle(&self) -> VkSwapchainKHR {
self.swapchain
}
}
impl<'a> Drop for Swapchain<'a> {
fn drop(&mut self) {
if !self.raw {
self.destroy();
}
}
}