use super::device::DeviceInner;
use super::image::{ImageUsage, ImageView};
use super::physical::PhysicalDevice;
use super::surface::{PresentMode, Surface};
use super::sync::Semaphore;
use super::{Device, Error, Format, Queue, Result, check};
use crate::raw::bindings::*;
use std::sync::Arc;
#[derive(Debug, Clone, Copy)]
pub struct SwapchainCreateInfo {
pub format: Format,
pub color_space: VkColorSpaceKHR,
pub width: u32,
pub height: u32,
pub min_image_count: u32,
pub image_usage: ImageUsage,
pub present_mode: PresentMode,
pub clipped: bool,
}
impl Default for SwapchainCreateInfo {
fn default() -> Self {
Self {
format: Format::B8G8R8A8_UNORM,
color_space: VkColorSpaceKHR::COLOR_SPACE_SRGB_NONLINEAR_KHR,
width: 800,
height: 600,
min_image_count: 2,
image_usage: ImageUsage::COLOR_ATTACHMENT,
present_mode: PresentMode::FIFO,
clipped: true,
}
}
}
pub struct Swapchain {
pub(crate) handle: VkSwapchainKHR,
pub(crate) device: Arc<DeviceInner>,
#[allow(dead_code)]
pub(crate) surface: Arc<super::instance::InstanceInner>,
pub(crate) format: Format,
pub(crate) extent: (u32, u32),
pub(crate) images: Vec<VkImage>,
}
impl Swapchain {
pub fn new(device: &Device, surface: &Surface, info: SwapchainCreateInfo) -> Result<Self> {
let create = device
.inner
.dispatch
.vkCreateSwapchainKHR
.ok_or(Error::MissingFunction("vkCreateSwapchainKHR"))?;
let create_info = VkSwapchainCreateInfoKHR {
sType: VkStructureType::STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
surface: surface.handle,
minImageCount: info.min_image_count,
imageFormat: info.format.0,
imageColorSpace: info.color_space,
imageExtent: VkExtent2D {
width: info.width,
height: info.height,
},
imageArrayLayers: 1,
imageUsage: info.image_usage.0,
imageSharingMode: VkSharingMode::SHARING_MODE_EXCLUSIVE,
preTransform: SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
compositeAlpha: COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
presentMode: info.present_mode.0,
clipped: if info.clipped { 1 } else { 0 },
oldSwapchain: 0,
..Default::default()
};
let mut handle: VkSwapchainKHR = 0;
check(unsafe {
create(
device.inner.handle,
&create_info,
std::ptr::null(),
&mut handle,
)
})?;
let get_images = device
.inner
.dispatch
.vkGetSwapchainImagesKHR
.ok_or(Error::MissingFunction("vkGetSwapchainImagesKHR"))?;
let mut count: u32 = 0;
check(unsafe {
get_images(
device.inner.handle,
handle,
&mut count,
std::ptr::null_mut(),
)
})?;
let mut images: Vec<VkImage> = vec![0; count as usize];
check(unsafe { get_images(device.inner.handle, handle, &mut count, images.as_mut_ptr()) })?;
Ok(Self {
handle,
device: Arc::clone(&device.inner),
surface: Arc::clone(&surface.instance),
format: info.format,
extent: (info.width, info.height),
images,
})
}
pub fn raw(&self) -> VkSwapchainKHR {
self.handle
}
pub fn format(&self) -> Format {
self.format
}
pub fn extent(&self) -> (u32, u32) {
self.extent
}
pub fn image_count(&self) -> u32 {
self.images.len() as u32
}
pub fn image_views(&self) -> Result<Vec<ImageView>> {
let create = self
.device
.dispatch
.vkCreateImageView
.ok_or(Error::MissingFunction("vkCreateImageView"))?;
let mut views = Vec::with_capacity(self.images.len());
for &image in &self.images {
let info = VkImageViewCreateInfo {
sType: VkStructureType::STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
image,
viewType: VkImageViewType::IMAGE_VIEW_TYPE_2D,
format: self.format.0,
components: VkComponentMapping {
r: VkComponentSwizzle::COMPONENT_SWIZZLE_IDENTITY,
g: VkComponentSwizzle::COMPONENT_SWIZZLE_IDENTITY,
b: VkComponentSwizzle::COMPONENT_SWIZZLE_IDENTITY,
a: VkComponentSwizzle::COMPONENT_SWIZZLE_IDENTITY,
},
subresourceRange: VkImageSubresourceRange {
aspectMask: IMAGE_ASPECT_COLOR_BIT,
baseMipLevel: 0,
levelCount: 1,
baseArrayLayer: 0,
layerCount: 1,
},
..Default::default()
};
let mut handle: VkImageView = 0;
check(unsafe { create(self.device.handle, &info, std::ptr::null(), &mut handle) })?;
views.push(ImageView {
handle,
device: Arc::clone(&self.device),
});
}
Ok(views)
}
pub fn acquire_next_image(
&self,
timeout_nanos: u64,
signal_semaphore: Option<&Semaphore>,
signal_fence: Option<&super::Fence>,
) -> Result<u32> {
let acquire = self
.device
.dispatch
.vkAcquireNextImageKHR
.ok_or(Error::MissingFunction("vkAcquireNextImageKHR"))?;
let mut index: u32 = 0;
let sem = signal_semaphore.map_or(0u64, Semaphore::raw);
let fence = signal_fence.map_or(0u64, super::Fence::raw);
check(unsafe {
acquire(
self.device.handle,
self.handle,
timeout_nanos,
sem,
fence,
&mut index,
)
})?;
Ok(index)
}
pub fn present(
&self,
queue: &Queue,
image_index: u32,
wait_semaphores: &[&Semaphore],
) -> Result<()> {
let present = self
.device
.dispatch
.vkQueuePresentKHR
.ok_or(Error::MissingFunction("vkQueuePresentKHR"))?;
let raw_waits: Vec<VkSemaphore> = wait_semaphores.iter().map(|s| s.raw()).collect();
let info = VkPresentInfoKHR {
sType: VkStructureType::STRUCTURE_TYPE_PRESENT_INFO_KHR,
waitSemaphoreCount: raw_waits.len() as u32,
pWaitSemaphores: if raw_waits.is_empty() {
std::ptr::null()
} else {
raw_waits.as_ptr()
},
swapchainCount: 1,
pSwapchains: &self.handle,
pImageIndices: &image_index,
..Default::default()
};
check(unsafe { present(queue.raw(), &info) })
}
pub fn pick_surface_format(
surface: &Surface,
physical: &PhysicalDevice,
) -> Result<(Format, VkColorSpaceKHR)> {
let formats = surface.formats(physical)?;
if formats.is_empty() {
return Err(Error::Vk(VkResult::ERROR_FORMAT_NOT_SUPPORTED));
}
for f in &formats {
if f.format() == Format::B8G8R8A8_SRGB
&& f.color_space() == VkColorSpaceKHR::COLOR_SPACE_SRGB_NONLINEAR_KHR
{
return Ok((f.format(), f.color_space()));
}
}
Ok((formats[0].format(), formats[0].color_space()))
}
}
impl Drop for Swapchain {
fn drop(&mut self) {
if let Some(destroy) = self.device.dispatch.vkDestroySwapchainKHR {
unsafe { destroy(self.device.handle, self.handle, std::ptr::null()) };
}
}
}