use crate::{
error::SarektResult,
renderer::{
config::PresentMode,
vulkan::{
images::ImageAndView,
queues::QueueFamilyIndices,
vulkan_renderer::{
surface::SurfaceAndExtension,
swap_chain::SwapchainAndExtension,
vulkan_core::{VulkanCoreStructures, VulkanDeviceStructures},
},
},
},
};
use ash::{version::DeviceV1_0, vk, Device};
use log::{info, warn};
use std::sync::Arc;
pub struct RenderTargetBundle {
pub swapchain_and_extension: SwapchainAndExtension, pub render_targets: Vec<ImageAndView>, pub extent: vk::Extent2D,
}
impl RenderTargetBundle {
pub fn new(
vulkan_core: &VulkanCoreStructures, device_bundle: &VulkanDeviceStructures,
requested_width: u32, requested_height: u32, requested_present_mode: PresentMode,
) -> SarektResult<RenderTargetBundle> {
let swapchain_extension = ash::extensions::khr::Swapchain::new(
vulkan_core.instance.as_ref(),
device_bundle.logical_device.as_ref(),
);
let (swapchain, format, extent) = Self::create_swapchain(
&vulkan_core.surface_and_extension,
&swapchain_extension,
device_bundle.physical_device,
&device_bundle.queue_families,
requested_width,
requested_height,
requested_present_mode,
None,
)?;
let swapchain_and_extension =
SwapchainAndExtension::new(swapchain, format, swapchain_extension);
let render_target_images = unsafe {
swapchain_and_extension
.swapchain_functions
.get_swapchain_images(swapchain_and_extension.swapchain)?
};
let render_targets = Self::create_render_target_image_views(
&device_bundle.logical_device,
render_target_images,
swapchain_and_extension.format,
)?;
Ok(RenderTargetBundle {
swapchain_and_extension,
render_targets,
extent,
})
}
pub fn acquire_next_image(
&self, timeout: u64, image_available_semaphore: vk::Semaphore, image_available_fence: vk::Fence,
) -> SarektResult<(u32, bool)> {
unsafe {
Ok(
self
.swapchain_and_extension
.swapchain_functions
.acquire_next_image(
self.swapchain_and_extension.swapchain,
timeout,
image_available_semaphore,
image_available_fence,
)?,
)
}
}
pub fn queue_present(
&self, image_index: usize, presentation_queue: vk::Queue, wait_semaphores: &[vk::Semaphore],
) -> SarektResult<()> {
let swapchains = [self.swapchain_and_extension.swapchain];
let image_indices = [image_index as u32];
let present_info = vk::PresentInfoKHR::builder()
.wait_semaphores(wait_semaphores)
.swapchains(&swapchains)
.image_indices(&image_indices)
.build();
unsafe {
self
.swapchain_and_extension
.swapchain_functions
.queue_present(presentation_queue, &present_info)?;
}
Ok(())
}
pub fn get_render_target_format(&self) -> vk::Format {
self.swapchain_and_extension.format
}
pub fn extent_is_equal_to(&self, width: u32, height: u32) -> bool {
self.extent.width == width && self.extent.height == height
}
pub unsafe fn recreate_swapchain(
&mut self, vulkan_core: &VulkanCoreStructures, device_bundle: &VulkanDeviceStructures,
requested_width: u32, requested_height: u32, requested_present_mode: PresentMode,
) -> SarektResult<(vk::SwapchainKHR, Vec<ImageAndView>)> {
let old_swapchain = self.swapchain_and_extension.swapchain;
let (new_swapchain, new_format, new_extent) = RenderTargetBundle::create_swapchain(
&vulkan_core.surface_and_extension,
&self.swapchain_and_extension.swapchain_functions,
device_bundle.physical_device,
&device_bundle.queue_families,
requested_width,
requested_height,
requested_present_mode,
Some(old_swapchain),
)?;
self.swapchain_and_extension.swapchain = new_swapchain;
self.swapchain_and_extension.format = new_format;
self.extent = new_extent;
let render_target_images = self
.swapchain_and_extension
.swapchain_functions
.get_swapchain_images(new_swapchain)?;
let mut render_targets = Self::create_render_target_image_views(
&device_bundle.logical_device,
render_target_images,
new_format,
)?;
std::mem::swap(&mut self.render_targets, &mut render_targets);
Ok((old_swapchain, render_targets))
}
pub unsafe fn cleanup_render_targets(
&self, device_bundle: &VulkanDeviceStructures, render_targets: &[ImageAndView],
swapchain: vk::SwapchainKHR,
) {
info!("Destrying render target views...");
for view in render_targets.iter() {
device_bundle
.logical_device
.destroy_image_view(view.view, None);
}
info!("Destrying swapchain...");
let swapchain_functions = &self.swapchain_and_extension.swapchain_functions;
swapchain_functions.destroy_swapchain(swapchain, None);
}
fn create_swapchain(
surface_and_extension: &SurfaceAndExtension,
swapchain_extension: &ash::extensions::khr::Swapchain, physical_device: vk::PhysicalDevice,
queue_family_indices: &QueueFamilyIndices, requested_width: u32, requested_height: u32,
requested_present_mode: PresentMode, old_swapchain: Option<vk::SwapchainKHR>,
) -> SarektResult<(vk::SwapchainKHR, vk::Format, vk::Extent2D)> {
let swapchain_support =
VulkanDeviceStructures::query_swap_chain_support(surface_and_extension, physical_device)?;
let format = Self::choose_swap_surface_format(&swapchain_support.formats);
let present_mode =
Self::choose_presentation_mode(&swapchain_support.present_modes, requested_present_mode);
let extent = Self::choose_swap_extent(
&swapchain_support.capabilities,
requested_width,
requested_height,
);
let max_image_count = swapchain_support.capabilities.max_image_count;
let max_image_count = if max_image_count == 0 {
u32::max_value()
} else {
max_image_count
};
let min_image_count = (swapchain_support.capabilities.min_image_count + 1).min(max_image_count);
let sharing_mode = if queue_family_indices.graphics_queue_family.unwrap()
!= queue_family_indices.presentation_queue_family.unwrap()
{
vk::SharingMode::CONCURRENT
} else {
vk::SharingMode::EXCLUSIVE
};
let swapchain_ci = vk::SwapchainCreateInfoKHR::builder()
.surface(surface_and_extension.surface)
.min_image_count(min_image_count)
.image_format(format.format)
.image_color_space(format.color_space)
.image_extent(extent)
.image_array_layers(1) .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) .image_sharing_mode(sharing_mode)
.queue_family_indices(&queue_family_indices.as_vec().unwrap())
.pre_transform(swapchain_support.capabilities.current_transform) .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) .present_mode(present_mode)
.clipped(true) .old_swapchain(old_swapchain.unwrap_or_else(vk::SwapchainKHR::null)) .build();
let swapchain = unsafe { swapchain_extension.create_swapchain(&swapchain_ci, None)? };
Ok((swapchain, format.format, extent))
}
fn choose_swap_surface_format(
available_formats: &[vk::SurfaceFormatKHR],
) -> vk::SurfaceFormatKHR {
*available_formats
.iter()
.find(|format| {
format.format == vk::Format::B8G8R8A8_UNORM
&& format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
})
.unwrap_or(&available_formats[0])
}
fn choose_presentation_mode(
available_presentation_modes: &[vk::PresentModeKHR], requested_present_mode: PresentMode,
) -> vk::PresentModeKHR {
let present_mode = *available_presentation_modes
.iter()
.find(|&pm| match (requested_present_mode, pm) {
(PresentMode::Mailbox, &vk::PresentModeKHR::MAILBOX) => true,
(PresentMode::Immediate, &vk::PresentModeKHR::IMMEDIATE) => true,
(PresentMode::Fifo, &vk::PresentModeKHR::FIFO) => true,
_ => false,
})
.unwrap_or(&vk::PresentModeKHR::FIFO);
info!("Selecting present mode: {:?}", present_mode);
present_mode
}
fn choose_swap_extent(
capabilities: &vk::SurfaceCapabilitiesKHR, requested_width: u32, requested_height: u32,
) -> vk::Extent2D {
if capabilities.current_extent.width != u32::max_value() {
return capabilities.current_extent;
}
let clipped_requested_width = requested_width.min(capabilities.max_image_extent.width);
let width = capabilities
.min_image_extent
.width
.max(clipped_requested_width);
let clipped_requested_height = requested_height.min(capabilities.max_image_extent.height);
let height = capabilities
.min_image_extent
.height
.max(clipped_requested_height);
if width != requested_width || height != requested_height {
warn!(
"Could not create a swapchain with the requested height and width, rendering to a \
resolution of {}x{} instead",
width, height
);
}
vk::Extent2D::builder().width(width).height(height).build()
}
fn create_render_target_image_views(
logical_device: &Arc<Device>, targets: Vec<vk::Image>, format: vk::Format,
) -> SarektResult<Vec<ImageAndView>> {
let mut views = Vec::with_capacity(targets.len());
for &image in targets.iter() {
let component_mapping = vk::ComponentMapping::default();
let image_subresource_range = vk::ImageSubresourceRange::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR) .base_mip_level(0) .level_count(1) .base_array_layer(0) .layer_count(1) .build();
let ci = vk::ImageViewCreateInfo::builder()
.image(image)
.view_type(vk::ImageViewType::TYPE_2D)
.format(format)
.components(component_mapping)
.subresource_range(image_subresource_range);
let view = unsafe { logical_device.create_image_view(&ci, None)? };
unsafe { views.push(ImageAndView::new(image, view)) };
}
Ok(views)
}
}