1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
//! Just the logic for acquiring and presenting swapchain images.
//!
//! It's nice to bundle this logic up into one spot - even if it is all still
//! exposed on the public api - because it ends up being so verbose.
use {
super::Swapchain, crate::graphics::GraphicsError, anyhow::Context, ash::vk,
ccthw_ash_instance::VulkanHandle,
};
/// Indicates that the swapchain needs a rebuild, or that the image was acquired
/// successfully.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum SwapchainStatus {
/// Completed the operation with the given swapchain index.
Index(usize),
/// Indicates that the swapchain needs to be rebuilt.
NeedsRebuild,
}
// Public API
// ----------
impl Swapchain {
/// Acquire the next swapchain image.
///
/// # Params
///
/// * `semaphore` - a semaphore to signal when the swapchain image is
/// available.
///
/// # Safety
///
/// The application must correctly handle a swapchain acquisition failure
/// and rebuild the swapchain on demand.
pub unsafe fn acquire_swapchain_image(
&self,
semaphore: vk::Semaphore,
fence: vk::Fence,
) -> Result<SwapchainStatus, GraphicsError> {
let result = self.swapchain_loader.acquire_next_image(
self.swapchain,
std::u64::MAX,
semaphore,
fence,
);
match result {
// index acquired and the swapchain is optimal
Ok((index, false)) => Ok(SwapchainStatus::Index(index as usize)),
// index acquired but the swapchain is suboptimal for the surface
Ok((_, true)) => {
log::debug!(
"Acquire Image: Swapchain suboptimal, needs rebuild."
);
Ok(SwapchainStatus::NeedsRebuild)
}
// the swapchain is lost and needs to be rebuilt
Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => {
log::debug!("Acquire Image: Swapchain lost, needs rebuild.");
Ok(SwapchainStatus::NeedsRebuild)
}
Err(_) => Err(GraphicsError::RuntimeError(
result
.context(
"Unexpected error while acquiring swapchain image!",
)
.err()
.unwrap(),
)),
}
}
/// Present a swapchain image to the screen.
///
/// # Safety
///
/// Unsafe because:
/// - the application must correctly handle a swapchain acquisition
/// failure and rebuild the swapchain on demand
/// - the application must transition the swapchain image to the correct
/// image layout. Typically this is done with a Render Pass.
pub unsafe fn present_swapchain_image(
&self,
index: usize,
wait_semaphores: &[vk::Semaphore],
) -> Result<SwapchainStatus, GraphicsError> {
let index_u32 = index as u32;
let present_info = vk::PresentInfoKHR {
p_wait_semaphores: wait_semaphores.as_ptr(),
wait_semaphore_count: wait_semaphores.len() as u32,
p_swapchains: &self.swapchain,
swapchain_count: 1,
p_image_indices: &index_u32,
..Default::default()
};
let result = self.swapchain_loader.queue_present(
*self.render_device.presentation_queue().raw(),
&present_info,
);
match result {
// presentation succeeded and the swapchain is still optimal
Ok(false) => Ok(SwapchainStatus::Index(index)),
// presentation succeeded but the swapchain is submoptimal
Ok(true) => {
log::debug!(
"Present Image: Swapchain is suboptimal and needs rebuild"
);
Ok(SwapchainStatus::NeedsRebuild)
}
// the swapchain is lost and needs to be rebuilt
Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => {
log::debug!("Present Image: Swapchain lost, needs rebuild.");
Ok(SwapchainStatus::NeedsRebuild)
}
Err(_) => Err(GraphicsError::RuntimeError(
result
.context(
"Unexpected error while presenting swapchain image!",
)
.err()
.unwrap(),
)),
}
}
}