use super::device::Device;
use super::pass::GraphicalPass;
use super::swapchain::Swapchain;
use winit::window::Window;
use std::sync::Arc;
pub use vulkano::pipeline::viewport::Viewport;
use vulkano::buffer::{BufferAccess, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferExecError, DynamicState};
use vulkano::descriptor::descriptor_set::DescriptorSetsCollection;
use vulkano::framebuffer::FramebufferAbstract;
use vulkano::sync::{GpuFuture, FlushError};
use vulkano::swapchain::{Swapchain as VlkSwapchain};
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::pipeline::input_assembly::Index;
use vulkano::pipeline::vertex::VertexSource;
pub struct Frame {
pub(super) device: Device,
pub(super) swapchain: Arc<VlkSwapchain<Arc<Window>>>,
pub(super) time: Box<dyn GpuFuture>,
pub(super) dynamic_state: DynamicState,
pub(super) commands: AutoCommandBufferBuilder,
pub(super) swapchain_index: usize,
}
pub struct PassInFrame<'a, P : ?Sized> {
pub(super) frame: Frame,
pub(super) pass: &'a GraphicalPass<P>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FrameFinishError {
Flush(FlushError),
Commands(CommandBufferExecError),
}
impl Frame {
pub fn begin(
mut device: Device,
swapchain: &Swapchain,
) -> Result<Frame, (Device, vulkano::swapchain::AcquireError)>
{
let used_swapchain = swapchain.swapchain.clone();
let (swapchain_index, _should_recreate, image_acquire_time) = match vulkano::swapchain::acquire_next_image(used_swapchain.clone(), None) {
Ok(result) => result,
Err(err) => return Err((device, err)),
};
let time: Box<dyn GpuFuture> = match device.before_frame.take() {
Some(mut time) => {
time.cleanup_finished();
Box::new(time.join(image_acquire_time))
},
None => Box::new(vulkano::sync::now(device.logical_device()).join(image_acquire_time)),
};
let commands = AutoCommandBufferBuilder::primary_one_time_submit(device.logical_device(), device.graphics_queue.family()).unwrap();
let frame = Frame {
device,
swapchain: used_swapchain,
dynamic_state: swapchain.dynamic_state.clone(),
time,
commands,
swapchain_index,
};
Ok(frame)
}
pub fn begin_pass<'a, P: ?Sized, F>(
mut self,
pass: &'a GraphicalPass<P>,
framebuffer: F,
viewport: Viewport,
clear_values: Vec<vulkano::format::ClearValue>)
-> PassInFrame<'a, P>
where
F : FramebufferAbstract + Send + Sync + Clone + 'static,
{
self.commands = self.commands.begin_render_pass(framebuffer, false, clear_values).unwrap();
self.dynamic_state.viewports = Some(vec![viewport]);
PassInFrame {
frame: self,
pass: pass,
}
}
#[inline]
pub fn finish(self) -> Result<Device, (Device, FrameFinishError)> {
let commands = self.commands.build().unwrap();
let after_execute = match self.time.then_execute(self.device.graphics_queue.clone(), commands) {
Ok(future) => future,
Err(err) => return Err((self.device, FrameFinishError::Commands(err))),
};
let after_flush = after_execute.then_swapchain_present(self.device.graphics_queue.clone(), self.swapchain, self.swapchain_index)
.then_signal_fence_and_flush();
let after_frame = match after_flush {
Ok(future) => future,
Err(err) => return Err((self.device, FrameFinishError::Flush(err))),
};
let device = Device { before_frame: Some(Box::new(after_frame)), .. self.device };
Ok(device)
}
}
impl<'a, P : ?Sized> PassInFrame<'a, P>
where
P : GraphicsPipelineAbstract + Send + Sync + 'static,
{
#[inline]
pub fn draw<VB, DSC, PC>(
mut self,
vertex_buffer: VB,
descriptor_sets: DSC,
push_constants: PC
) -> Self
where
P : VertexSource<VB>,
DSC : DescriptorSetsCollection,
{
self.frame.commands = self.frame.commands.draw(self.pass.pipeline.clone(), &self.frame.dynamic_state, vertex_buffer, descriptor_sets, push_constants).unwrap();
self
}
#[inline]
pub fn draw_indexed<VB, IB, DSC, PC, I>(
mut self,
vertex_buffer: VB,
index_buffer: IB,
descriptor_sets: DSC,
push_constants: PC
) -> Self
where
P : VertexSource<VB>,
DSC : DescriptorSetsCollection,
IB : BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static,
I : Index + 'static,
{
self.frame.commands = self.frame.commands.draw_indexed(self.pass.pipeline.clone(), &self.frame.dynamic_state, vertex_buffer, index_buffer, descriptor_sets, push_constants).unwrap();
self
}
#[inline]
pub fn finish_pass(self) -> Frame {
let commands = self.frame.commands.end_render_pass().unwrap();
Frame { commands, .. self.frame }
}
}