use std::error::Error;
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use ahash::HashMap;
use educe::Educe;
use itertools::Itertools;
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
use smallvec::SmallVec;
use tracing::warn;
use vulkano::command_buffer::CommandBufferExecFuture;
use vulkano::image::view::ImageView;
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass};
use vulkano::swapchain::{PresentFuture, Swapchain, SwapchainAcquireFuture, SwapchainPresentInfo};
use vulkano::sync::future::{FenceSignalFuture, JoinFuture};
use vulkano::sync::GpuFuture;
use vulkano::{sync, Validated, VulkanError};
use vulkano::device::{DeviceOwned, Queue};
use vulkano::image::{Image, ImageCreateInfo, ImageUsage};
use vulkano::memory::allocator::AllocationCreateInfo;
use crate::render::attachment::{AttachmentDescriptor, AttachmentType};
use crate::render::{EngineDevice, RenderTarget, VulkanoError};
type FrameFence = FenceSignalFuture<PresentFuture<CommandBufferExecFuture<
JoinFuture<Box<dyn GpuFuture + Send + Sync>, SwapchainAcquireFuture>
>>>;
#[derive(Educe)]
#[educe(Debug)]
pub struct EngineFramebuffer {
index: usize,
vk_queue: Arc<Queue>,
vk_swapchain: Arc<Swapchain>,
vk_framebuffer: Arc<Framebuffer>,
attachments: Vec<AttachmentType>,
name_map: Arc<HashMap<String, u32>>,
#[educe(Debug(ignore))]
fence: Mutex<Option<Arc<FrameFence>>>,
}
impl EngineFramebuffer {
fn new(
index: usize,
device: &Arc<EngineDevice>,
vk_swapchain: Arc<Swapchain>,
vk_render_pass: Arc<RenderPass>,
output_image: Arc<Image>,
attachment_create_info: Vec<ImageCreateInfo>,
name_map: Arc<HashMap<String, u32>>,
) -> Result<Arc<Self>, Validated<VulkanoError>> {
let (attachments, framebuffer_images): (Vec<_>, Vec<_>) = attachment_create_info.into_iter()
.map(move |create_info| {
if create_info.usage.contains(ImageUsage::TRANSIENT_ATTACHMENT) {
let image_view = ImageView::new_default(
Image::new(
device.memory_allocator().clone(),
create_info,
AllocationCreateInfo::default(),
).map_err(VulkanoError::from_validated)?
).map_err(VulkanoError::from_validated)?;
Ok::<_, Validated<VulkanoError>>((
AttachmentType::Transient(image_view.clone()),
image_view,
))
} else {
let image_view = ImageView::new_default(
output_image.clone()
).map_err(VulkanoError::from_validated)?;
Ok::<_, Validated<VulkanoError>>((
AttachmentType::Output,
image_view,
))
}
})
.process_results(|iter| iter.unzip())?;
let vk_framebuffer = Framebuffer::new(
vk_render_pass,
FramebufferCreateInfo {
attachments: framebuffer_images,
..Default::default()
},
).map_err(VulkanoError::from_validated)?;
Ok(Arc::new(Self {
index,
vk_queue: device.queue().clone(),
vk_swapchain,
vk_framebuffer,
attachments,
name_map,
fence: Mutex::new(None),
}))
}
pub fn for_images(
target: &Arc<dyn RenderTarget>,
device: &Arc<EngineDevice>,
vk_swapchain: &Arc<Swapchain>,
vk_render_pass: &Arc<RenderPass>,
images: Vec<Arc<Image>>,
name_map: HashMap<String, u32>,
) -> Result<SmallVec<[Arc<EngineFramebuffer>; 3]>, Validated<VulkanoError>> {
let mut create_infos = vk_render_pass.attachments().iter()
.map(|atch| ImageCreateInfo {
extent: target.extent().fixed_resize::<3, 1>(1).into(),
format: atch.format,
usage: ImageUsage::empty(),
..Default::default()
}).collect::<Vec<_>>();
for subpass in vk_render_pass.subpasses().iter() {
for color_atch in subpass.color_attachments.iter().flatten() {
create_infos[color_atch.attachment as usize].usage = ImageUsage::COLOR_ATTACHMENT;
}
for depth_stencil_atch in subpass.depth_stencil_attachment.iter() {
create_infos[depth_stencil_atch.attachment as usize].usage
= ImageUsage::DEPTH_STENCIL_ATTACHMENT | ImageUsage::TRANSIENT_ATTACHMENT;
}
for input_atch in subpass.input_attachments.iter().flatten() {
create_infos[input_atch.attachment as usize].usage
|= ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::INPUT_ATTACHMENT;
}
}
let name_map = Arc::new(name_map);
images.into_iter().enumerate()
.map(|(idx, image)| {
EngineFramebuffer::new(
idx,
device,
vk_swapchain.clone(),
vk_render_pass.clone(),
image,
create_infos.clone(),
name_map.clone(),
)
})
.collect::<Result<SmallVec<_>, _>>()
}
#[inline]
pub fn index(&self) -> usize { self.index }
#[inline]
pub fn wait_ready(&self) {
if let Some(fence) = &*self.fence.lock() {
fence.wait(None).unwrap();
}
}
#[inline]
pub fn get_future(&self) -> Box<dyn GpuFuture + Send + Sync> {
if let Some(fence) = self.fence.lock().clone() {
fence.boxed_send_sync()
} else {
let mut now = sync::now(self.vk_swapchain.device().clone());
now.cleanup_finished();
now.boxed_send_sync()
}
}
#[inline]
pub(in crate::render) fn flush_command(
&self,
command_future: CommandBufferExecFuture<JoinFuture<Box<dyn GpuFuture + Send + Sync>, SwapchainAcquireFuture>>,
) -> Result<(), VulkanError> {
let mut suboptimal = false;
let result = command_future
.then_swapchain_present(
self.vk_queue.clone(),
SwapchainPresentInfo::swapchain_image_index(self.vk_swapchain.clone(), self.index as u32),
).then_signal_fence_and_flush()
.map_err(Validated::unwrap);
let future = match result {
Ok(value) => Some(Arc::new(value)),
Err(VulkanError::OutOfDate) => {
suboptimal = true;
None
},
Err(error) => {
warn!(?error, "Failed to flush future");
None
}
};
*self.fence.lock() = future;
if suboptimal {
return Err(VulkanError::OutOfDate)
}
Ok(())
}
#[inline]
pub fn buffer(&self) -> &Arc<Framebuffer> { &self.vk_framebuffer }
#[inline]
pub fn get_attachment(&self, name: impl Into<String>) -> Option<AttachmentType> {
let name = name.into();
let atch_idx = self.name_map.get(&name)?.clone();
Some(self.attachments.get(atch_idx as usize)?.clone())
}
}
#[derive(Debug)]
pub struct Frame<T> {
buffer: Arc<EngineFramebuffer>,
value: T,
}
impl<T> Frame<T> {
pub fn new(buffer: Arc<EngineFramebuffer>, value: T) -> Self {
Self {
buffer,
value,
}
}
#[inline]
pub fn index(&self) -> usize {
self.buffer.index()
}
}
impl<T> Deref for Frame<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T> DerefMut for Frame<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<R, T> AsRef<R> for Frame<T>
where
R: ?Sized,
<Frame<T> as Deref>::Target: AsRef<R>,
{
#[inline]
fn as_ref(&self) -> &R {
self.deref().as_ref()
}
}
impl<R, T> AsMut<R> for Frame<T>
where
<Frame<T> as Deref>::Target: AsMut<R>,
{
#[inline]
fn as_mut(&mut self) -> &mut R {
self.deref_mut().as_mut()
}
}
#[derive(Debug, Clone, Copy)]
pub enum FrameSetUpdateStyle {
KeepExisting,
RecreateAll,
}
impl Default for FrameSetUpdateStyle {
#[inline]
fn default() -> Self {
Self::RecreateAll
}
}
type CreateFrameDataFn<T, E> = dyn (
Fn(&EngineFramebuffer) -> Result<T, E>
) + Send + Sync + 'static;
#[derive(Educe)]
#[educe(Debug)]
pub struct FrameSet<T, E>
where
T: Send + Sync + 'static,
E: Error + 'static,
{
manager: Arc<dyn FrameManager>,
update_style: FrameSetUpdateStyle,
#[educe(Debug(ignore))]
create_frame_data: Box<CreateFrameDataFn<T, E>>,
frames: Mutex<Option<SmallVec<[Frame<T>; 3]>>>,
}
impl<T, E> FrameSet<T, E>
where
T: Send + Sync + 'static,
E: Error + 'static,
{
fn create_frames(
manager: &Arc<dyn FrameManager>,
existing_frames: Option<SmallVec<[Frame<T>; 3]>>,
create_frame_data: &Box<CreateFrameDataFn<T, E>>,
) -> Result<SmallVec<[Frame<T>; 3]>, E> {
if let Some(existing_frames) = existing_frames {
existing_frames.into_iter()
.map(|v| Some(v))
.chain(std::iter::repeat_with(|| None::<Frame<T>>))
.zip(manager.framebuffers())
.map(|(existing_frame, framebuffer)| {
if let Some(frame) = existing_frame {
Ok(frame)
} else {
create_frame_data(&*framebuffer)
.map(|value| Frame::new(framebuffer, value))
}
})
.collect::<Result<SmallVec<_>, _>>()
} else {
manager.framebuffers().into_iter()
.map(|framebuffer| {
create_frame_data(&*framebuffer)
.map(|value| Frame::new(framebuffer.clone(), value))
})
.collect::<Result<SmallVec<_>, _>>()
}
}
#[inline]
pub fn new(
manager: Arc<dyn FrameManager>,
create_frame_data: impl (Fn(&EngineFramebuffer) -> Result<T, E>) + Send + Sync + 'static,
) -> Result<Arc<Self>, E> {
Self::with_update_style(
manager,
FrameSetUpdateStyle::default(),
create_frame_data,
)
}
pub fn with_update_style(
manager: Arc<dyn FrameManager>,
update_style: FrameSetUpdateStyle,
create_frame_data: impl (Fn(&EngineFramebuffer) -> Result<T, E>) + Send + Sync + 'static,
) -> Result<Arc<Self>, E> {
let frameset = Self::with_config_unregistered(
manager.clone(),
update_style,
create_frame_data,
)?;
manager.register_frameset(frameset.clone().into());
Ok(frameset)
}
#[inline]
pub fn new_unregistered(
manager: Arc<dyn FrameManager>,
create_frame_data: impl (Fn(&EngineFramebuffer) -> Result<T, E>) + Send + Sync + 'static,
) -> Result<Arc<Self>, E> {
Self::with_config_unregistered(
manager,
FrameSetUpdateStyle::default(),
create_frame_data,
)
}
pub fn with_config_unregistered(
manager: Arc<dyn FrameManager>,
update_style: FrameSetUpdateStyle,
create_frame_data: impl (Fn(&EngineFramebuffer) -> Result<T, E>) + Send + Sync + 'static,
) -> Result<Arc<Self>, E> {
let create_frame_data: Box<CreateFrameDataFn<T, E>> = Box::new(create_frame_data);
let frames = Mutex::new(Some(Self::create_frames(
&manager,
None,
&create_frame_data,
)?));
Ok(Arc::new(Self {
manager: manager.clone(),
update_style,
create_frame_data,
frames,
}))
}
#[inline]
pub fn recreate(&self) -> Result<(), E> {
let mut frames = self.frames.lock();
match self.update_style {
FrameSetUpdateStyle::KeepExisting => {
let existing_frames = frames.take();
*frames = Some(Self::create_frames(
&self.manager,
existing_frames,
&self.create_frame_data,
)?)
},
FrameSetUpdateStyle::RecreateAll => {
*frames = Some(Self::create_frames(
&self.manager,
None,
&self.create_frame_data,
)?)
}
}
Ok(())
}
#[inline]
pub fn current(&self) -> MappedMutexGuard<Frame<T>> {
let current_frame_idx = self.manager.current_idx();
MutexGuard::map(self.frames.lock(), |frames| {
&mut frames.as_mut().unwrap()[current_frame_idx]
})
}
#[inline]
pub fn current_idx(&self) -> usize {
self.manager.current_idx()
}
#[inline]
pub fn get(&self, frame_idx: usize) -> Option<MappedMutexGuard<Frame<T>>> {
let guard = self.frames.lock();
if frame_idx < guard.as_ref().unwrap().len() {
Some(MutexGuard::map(guard, |frames| {
&mut frames.as_mut().unwrap()[frame_idx]
}))
} else {
None
}
}
#[inline]
pub fn for_each<F>(&self, f: F)
where
F: FnMut(&mut Frame<T>)
{
self.frames.lock().as_mut().unwrap().iter_mut().for_each(f)
}
}
#[derive(Educe)]
#[educe(Debug)]
pub struct FrameSetRef {
frame_type: &'static str,
#[educe(Debug(ignore))]
recreate_fn: Box<dyn (Fn() -> bool) + Send + Sync + 'static>,
}
impl FrameSetRef {
pub fn new<T, E>(frameset: Arc<FrameSet<T, E>>) -> Self
where
T: Send + Sync + 'static,
E: Error + 'static,
{
let weak = Arc::downgrade(&frameset);
Self {
frame_type: std::any::type_name::<T>(),
recreate_fn: Box::new(move || {
if let Some(frameset) = weak.upgrade() {
match frameset.recreate() {
Ok(_) => {},
Err(error) => {
warn!(?error, "Failed to recreate frameset");
}
}
true
} else {
false
}
}),
}
}
pub fn recreate(&self) -> bool {
(self.recreate_fn)()
}
}
impl<T, E> From<Arc<FrameSet<T, E>>> for FrameSetRef
where
T: Send + Sync + 'static,
E: Error + 'static,
{
#[inline]
fn from(value: Arc<FrameSet<T, E>>) -> Self {
FrameSetRef::new(value)
}
}
pub trait FrameManager: Debug + Send + Sync + 'static {
fn current_idx(&self) -> usize;
fn framebuffer(&self, frame_idx: usize) -> Option<Arc<EngineFramebuffer>>;
fn framebuffers(&self) -> SmallVec<[Arc<EngineFramebuffer>; 3]>;
fn register_frameset(&self, frameset: FrameSetRef);
}
pub trait FrameManagerExt {
fn attachment_descriptor(&self, input_name: impl Into<String>) -> Arc<AttachmentDescriptor>;
}
impl FrameManagerExt for Arc<dyn FrameManager> {
#[inline]
fn attachment_descriptor(&self, input_name: impl Into<String>) -> Arc<AttachmentDescriptor> {
Arc::new(AttachmentDescriptor::new(
self.clone(),
input_name,
))
}
}
impl<M: FrameManager> FrameManagerExt for Arc<M> {
#[inline]
fn attachment_descriptor(&self, input_name: impl Into<String>) -> Arc<AttachmentDescriptor> {
Arc::new(AttachmentDescriptor::new(
self.clone(),
input_name,
))
}
}