|
|
@ -108,6 +108,7 @@ pub struct VkProcessor<'a> {
|
|
|
|
pub render_pass: Option<Arc<RenderPassAbstract + Send + Sync>>,
|
|
|
|
pub render_pass: Option<Arc<RenderPassAbstract + Send + Sync>>,
|
|
|
|
pub vertex_buffer: Option<Arc<(dyn BufferAccess + std::marker::Send + std::marker::Sync + 'static)>>,
|
|
|
|
pub vertex_buffer: Option<Arc<(dyn BufferAccess + std::marker::Send + std::marker::Sync + 'static)>>,
|
|
|
|
pub dynamic_state: DynamicState,
|
|
|
|
pub dynamic_state: DynamicState,
|
|
|
|
|
|
|
|
pub previous_frame: Box<dyn GpuFuture>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> VkProcessor<'a> {
|
|
|
|
impl<'a> VkProcessor<'a> {
|
|
|
@ -134,7 +135,7 @@ impl<'a> VkProcessor<'a> {
|
|
|
|
physical: physical.clone(),
|
|
|
|
physical: physical.clone(),
|
|
|
|
pipeline: Option::None,
|
|
|
|
pipeline: Option::None,
|
|
|
|
compute_pipeline: Option::None,
|
|
|
|
compute_pipeline: Option::None,
|
|
|
|
device: device,
|
|
|
|
device: device.clone(),
|
|
|
|
queue: queue,
|
|
|
|
queue: queue,
|
|
|
|
queues: queues,
|
|
|
|
queues: queues,
|
|
|
|
set: Option::None,
|
|
|
|
set: Option::None,
|
|
|
@ -147,6 +148,7 @@ impl<'a> VkProcessor<'a> {
|
|
|
|
render_pass: Option::None,
|
|
|
|
render_pass: Option::None,
|
|
|
|
vertex_buffer: Option::None,
|
|
|
|
vertex_buffer: Option::None,
|
|
|
|
dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None },
|
|
|
|
dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None },
|
|
|
|
|
|
|
|
previous_frame: Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -373,7 +375,7 @@ impl<'a> VkProcessor<'a> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn run_loop(&mut self, surface: &'a Arc<Surface<Window>>) {
|
|
|
|
pub fn run(&mut self, surface: &'a Arc<Surface<Window>>, mut frame_future: Box<dyn GpuFuture>) -> Box<dyn GpuFuture> {
|
|
|
|
|
|
|
|
|
|
|
|
let mut framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(),
|
|
|
|
let mut framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(),
|
|
|
|
self.render_pass.clone().unwrap().clone(),
|
|
|
|
self.render_pass.clone().unwrap().clone(),
|
|
|
@ -381,140 +383,90 @@ impl<'a> VkProcessor<'a> {
|
|
|
|
|
|
|
|
|
|
|
|
let mut recreate_swapchain = false;
|
|
|
|
let mut recreate_swapchain = false;
|
|
|
|
|
|
|
|
|
|
|
|
// In the loop below we are going to submit commands to the GPU. Submitting a command produces
|
|
|
|
// The docs said to call this on each loop.
|
|
|
|
// an object that implements the `GpuFuture` trait, which holds the resources for as long as
|
|
|
|
frame_future.cleanup_finished();
|
|
|
|
// they are in use by the GPU.
|
|
|
|
|
|
|
|
//
|
|
|
|
// Whenever the window resizes we need to recreate everything dependent on the window size.
|
|
|
|
// Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to avoid
|
|
|
|
// In this example that includes the swapchain, the framebuffers and the dynamic state viewport.
|
|
|
|
// that, we store the submission of the previous frame here.
|
|
|
|
if recreate_swapchain {
|
|
|
|
let mut previous_frame_end = Box::new(sync::now(self.device.clone())) as Box<dyn GpuFuture>;
|
|
|
|
self.recreate_swapchain(surface);
|
|
|
|
|
|
|
|
framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(),
|
|
|
|
// loop {
|
|
|
|
self.render_pass.clone().unwrap().clone(),
|
|
|
|
// It is important to call this function from time to time, otherwise resources will keep
|
|
|
|
&mut self.dynamic_state);
|
|
|
|
// accumulating and you will eventually reach an out of memory error.
|
|
|
|
recreate_swapchain = false;
|
|
|
|
// Calling this function polls various fences in order to determine what the GPU has
|
|
|
|
}
|
|
|
|
// already processed, and frees the resources that are no longer needed.
|
|
|
|
|
|
|
|
// already processed, and frees the resources that are no longer needed.
|
|
|
|
|
|
|
|
previous_frame_end.cleanup_finished();
|
|
|
|
// This function can block if no image is available. The parameter is an optional timeout
|
|
|
|
|
|
|
|
// after which the function call will return an error.
|
|
|
|
// Whenever the window resizes we need to recreate everything dependent on the window size.
|
|
|
|
let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(self.swapchain.clone().unwrap().clone(), None) {
|
|
|
|
// In this example that includes the swapchain, the framebuffers and the dynamic state viewport.
|
|
|
|
Ok(r) => r,
|
|
|
|
if recreate_swapchain {
|
|
|
|
Err(AcquireError::OutOfDate) => {
|
|
|
|
self.recreate_swapchain(surface);
|
|
|
|
recreate_swapchain = true;
|
|
|
|
framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(),
|
|
|
|
//continue;
|
|
|
|
self.render_pass.clone().unwrap().clone(),
|
|
|
|
panic!("Weird thing");
|
|
|
|
&mut self.dynamic_state);
|
|
|
|
|
|
|
|
recreate_swapchain = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(err) => panic!("{:?}", err)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Specify the color to clear the framebuffer with i.e. blue
|
|
|
|
|
|
|
|
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Before we can draw on the output, we have to *acquire* an image from the swapchain. If
|
|
|
|
{
|
|
|
|
// no image is available (which happens if you submit draw commands too quickly), then the
|
|
|
|
// In order to draw, we have to build a *command buffer*. The command buffer object holds
|
|
|
|
// function will block.
|
|
|
|
// the list of commands that are going to be executed.
|
|
|
|
// This operation returns the index of the image that we are allowed to draw upon.
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// This function can block if no image is available. The parameter is an optional timeout
|
|
|
|
// Building a command buffer is an expensive operation (usually a few hundred
|
|
|
|
// after which the function call will return an error.
|
|
|
|
// microseconds), but it is known to be a hot path in the driver and is expected to be
|
|
|
|
let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(self.swapchain.clone().unwrap().clone(), None) {
|
|
|
|
// optimized.
|
|
|
|
Ok(r) => r,
|
|
|
|
//
|
|
|
|
Err(AcquireError::OutOfDate) => {
|
|
|
|
// Note that we have to pass a queue family when we create the command buffer. The command
|
|
|
|
|
|
|
|
// buffer will only be executable on that given queue family.
|
|
|
|
|
|
|
|
let mut v = Vec::new();
|
|
|
|
|
|
|
|
v.push(self.vertex_buffer.clone().unwrap().clone());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let command_buffer =
|
|
|
|
|
|
|
|
AutoCommandBufferBuilder::primary_one_time_submit(self.device.clone(), self.queue.family())
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.dispatch([self.xy.0, self.xy.1, 1],
|
|
|
|
|
|
|
|
self.compute_pipeline.clone().unwrap().clone(),
|
|
|
|
|
|
|
|
self.set.clone().unwrap().clone(), ()).unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values)
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.draw(self.pipeline.clone().unwrap().clone(), &self.dynamic_state, v, (), ())
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.end_render_pass()
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.build().unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wait on the previous frame, then execute the command buffer and present the image
|
|
|
|
|
|
|
|
let future = frame_future.join(acquire_future)
|
|
|
|
|
|
|
|
.then_execute(self.queue.clone(), command_buffer).unwrap()
|
|
|
|
|
|
|
|
.then_swapchain_present(self.queue.clone(), self.swapchain.clone().unwrap().clone(), image_num)
|
|
|
|
|
|
|
|
.then_signal_fence_and_flush();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match future {
|
|
|
|
|
|
|
|
Ok(future) => {
|
|
|
|
|
|
|
|
(Box::new(future) as Box<_>)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(FlushError::OutOfDate) => {
|
|
|
|
recreate_swapchain = true;
|
|
|
|
recreate_swapchain = true;
|
|
|
|
//continue;
|
|
|
|
(Box::new(sync::now(self.device.clone())) as Box<_>)
|
|
|
|
panic!("Weird thing");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => panic!("{:?}", err)
|
|
|
|
Err(e) => {
|
|
|
|
};
|
|
|
|
println!("{:?}", e);
|
|
|
|
|
|
|
|
(Box::new(sync::now(self.device.clone())) as Box<_>)
|
|
|
|
// Specify the color to clear the framebuffer with i.e. blue
|
|
|
|
|
|
|
|
let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// In order to draw, we have to build a *command buffer*. The command buffer object holds
|
|
|
|
|
|
|
|
// the list of commands that are going to be executed.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Building a command buffer is an expensive operation (usually a few hundred
|
|
|
|
|
|
|
|
// microseconds), but it is known to be a hot path in the driver and is expected to be
|
|
|
|
|
|
|
|
// optimized.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Note that we have to pass a queue family when we create the command buffer. The command
|
|
|
|
|
|
|
|
// buffer will only be executable on that given queue family.
|
|
|
|
|
|
|
|
let mut v = Vec::new();
|
|
|
|
|
|
|
|
v.push(self.vertex_buffer.clone().unwrap().clone());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let command_buffer =
|
|
|
|
|
|
|
|
AutoCommandBufferBuilder::primary_one_time_submit(self.device.clone(), self.queue.family())
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.dispatch([self.xy.0, self.xy.1, 1],
|
|
|
|
|
|
|
|
self.compute_pipeline.clone().unwrap().clone(),
|
|
|
|
|
|
|
|
self.set.clone().unwrap().clone(), ()).unwrap()
|
|
|
|
|
|
|
|
// Before we can draw, we have to *enter a render pass*. There are two methods to do
|
|
|
|
|
|
|
|
// this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is
|
|
|
|
|
|
|
|
// not covered here.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// The third parameter builds the list of values to clear the attachments with. The API
|
|
|
|
|
|
|
|
// is similar to the list of attachments when building the framebuffers, except that
|
|
|
|
|
|
|
|
// only the attachments that use `load: Clear` appear in the list.
|
|
|
|
|
|
|
|
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values)
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We are now inside the first subpass of the render pass. We add a draw command.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// The last two parameters contain the list of resources to pass to the shaders.
|
|
|
|
|
|
|
|
// Since we used an `EmptyPipeline` object, the objects have to be `()`.
|
|
|
|
|
|
|
|
.draw(self.pipeline.clone().unwrap().clone(), &self.dynamic_state, v, (), ())
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We leave the render pass by calling `draw_end`. Note that if we had multiple
|
|
|
|
|
|
|
|
// subpasses we could have called `next_inline` (or `next_secondary`) to jump to the
|
|
|
|
|
|
|
|
// next subpass.
|
|
|
|
|
|
|
|
.end_render_pass()
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Finish building the command buffer by calling `build`.
|
|
|
|
|
|
|
|
.build().unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let future = previous_frame_end.join(acquire_future)
|
|
|
|
|
|
|
|
.then_execute(self.queue.clone(), command_buffer).unwrap()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The color output is now expected to contain our triangle. But in order to show it on
|
|
|
|
|
|
|
|
// the screen, we have to *present* the image by calling `present`.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// This function does not actually present the image immediately. Instead it submits a
|
|
|
|
|
|
|
|
// present command at the end of the queue. This means that it will only be presented once
|
|
|
|
|
|
|
|
// the GPU has finished executing the command buffer that draws the triangle.
|
|
|
|
|
|
|
|
.then_swapchain_present(self.queue.clone(), self.swapchain.clone().unwrap().clone(), image_num)
|
|
|
|
|
|
|
|
.then_signal_fence_and_flush();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match future {
|
|
|
|
|
|
|
|
Ok(future) => {
|
|
|
|
|
|
|
|
previous_frame_end = Box::new(future) as Box<_>;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(FlushError::OutOfDate) => {
|
|
|
|
|
|
|
|
recreate_swapchain = true;
|
|
|
|
|
|
|
|
previous_frame_end = Box::new(sync::now(self.device.clone())) as Box<_>;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
|
|
println!("{:?}", e);
|
|
|
|
|
|
|
|
previous_frame_end = Box::new(sync::now(self.device.clone())) as Box<_>;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// Handling the window events in order to close the program when the user wants to close
|
|
|
|
|
|
|
|
// it.
|
|
|
|
|
|
|
|
let mut done = true;
|
|
|
|
|
|
|
|
// events_loop.poll_events(|ev| {
|
|
|
|
|
|
|
|
// match ev {
|
|
|
|
|
|
|
|
// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
|
|
|
|
|
|
|
|
// Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
|
|
|
|
|
|
|
|
// _ => ()
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
if done { return; }
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn load_buffers(&mut self, image_filename: String)
|
|
|
|
pub fn load_buffers(&mut self, image_filename: String)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let project_root =
|
|
|
|
let project_root =
|
|
|
|