From 5751965ce35d7e93916c683a3ec3488f3115ed27 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Tue, 16 Jul 2019 21:15:02 -0700 Subject: [PATCH] got everything worked out in the loop. I guess next will be to swap the compute buffer to the image buffer --- src/main.rs | 34 +++++++- src/vkprocessor.rs | 208 +++++++++++++++++---------------------------- 2 files changed, 110 insertions(+), 132 deletions(-) diff --git a/src/main.rs b/src/main.rs index 74da1ad2..f6ed6eee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ use sfml::graphics::{ Color, RenderTarget, RenderWindow, }; use sfml::system::*; -use sfml::window::{Event, Key, Style}; +use sfml::window::{Key, Style}; use sfml::window::mouse::*; use sfml::window::mouse; @@ -43,9 +43,10 @@ use vulkano::sync::GpuFuture; use shaderc::CompileOptions; use shade_runner::CompileError; use crate::workpiece::{WorkpieceLoader, Workpiece}; -use winit::{EventsLoop, WindowBuilder}; +use winit::{EventsLoop, WindowBuilder, WindowEvent, Event}; use vulkano_win::VkSurfaceBuild; + mod slider; mod timer; mod input; @@ -90,6 +91,15 @@ fn main() { let mut mouse_xy = Vector2i::new(0,0); + + + + + + + let mut s = Box::new(sync::now(processor.device.clone())) as Box; + + while let Some(p) = window.get_position() { // Event::MouseButtonPressed { button, x, y} => { @@ -124,9 +134,25 @@ fn main() { accumulator_time -= step_size; } - processor.run_loop(&surface); - print!("adosfijqwe"); + let mut exit = false; + events_loop.poll_events(|ev| { + match ev { + Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => + { + exit = true; + }, + Event::WindowEvent { event: WindowEvent::Resized(_), .. } => { + processor.recreate_swapchain(&surface); + }, + _ => () + } + }); + + if exit { + return; + } + s = processor.run(&surface, s); } } diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index 807ebaac..32bc91b5 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -108,6 +108,7 @@ pub struct VkProcessor<'a> { pub render_pass: Option>, pub vertex_buffer: Option>, pub dynamic_state: DynamicState, + pub previous_frame: Box, } impl<'a> VkProcessor<'a> { @@ -134,7 +135,7 @@ impl<'a> VkProcessor<'a> { physical: physical.clone(), pipeline: Option::None, compute_pipeline: Option::None, - device: device, + device: device.clone(), queue: queue, queues: queues, set: Option::None, @@ -147,6 +148,7 @@ impl<'a> VkProcessor<'a> { render_pass: Option::None, vertex_buffer: Option::None, dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None }, + previous_frame: Box::new(sync::now(device.clone())) as Box, } } @@ -373,7 +375,7 @@ impl<'a> VkProcessor<'a> { } - pub fn run_loop(&mut self, surface: &'a Arc>) { + pub fn run(&mut self, surface: &'a Arc>, mut frame_future: Box) -> Box { let mut framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), self.render_pass.clone().unwrap().clone(), @@ -381,140 +383,90 @@ impl<'a> VkProcessor<'a> { let mut recreate_swapchain = false; - // In the loop below we are going to submit commands to the GPU. Submitting a command produces - // an object that implements the `GpuFuture` trait, which holds the resources for as long as - // they are in use by the GPU. - // - // Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to avoid - // that, we store the submission of the previous frame here. - let mut previous_frame_end = Box::new(sync::now(self.device.clone())) as Box; - - // loop { - // It is important to call this function from time to time, otherwise resources will keep - // accumulating and you will eventually reach an out of memory error. - // 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(); - - // Whenever the window resizes we need to recreate everything dependent on the window size. - // In this example that includes the swapchain, the framebuffers and the dynamic state viewport. - if recreate_swapchain { - self.recreate_swapchain(surface); - framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), - self.render_pass.clone().unwrap().clone(), - &mut self.dynamic_state); - recreate_swapchain = false; + // The docs said to call this on each loop. + frame_future.cleanup_finished(); + + // Whenever the window resizes we need to recreate everything dependent on the window size. + // In this example that includes the swapchain, the framebuffers and the dynamic state viewport. + if recreate_swapchain { + self.recreate_swapchain(surface); + framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), + self.render_pass.clone().unwrap().clone(), + &mut self.dynamic_state); + recreate_swapchain = false; + } + + + // This function can block if no image is available. The parameter is an optional timeout + // after which the function call will return an error. + let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(self.swapchain.clone().unwrap().clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + recreate_swapchain = true; + //continue; + panic!("Weird thing"); } + 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 - // function will block. - // This operation returns the index of the image that we are allowed to draw upon. + { + // 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. // - // This function can block if no image is available. The parameter is an optional timeout - // after which the function call will return an error. - let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(self.swapchain.clone().unwrap().clone(), None) { - Ok(r) => r, - Err(AcquireError::OutOfDate) => { + // 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() + + .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; - //continue; - panic!("Weird thing"); + (Box::new(sync::now(self.device.clone())) as Box<_>) } - 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()); - - - { - // 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<_>; - } + Err(e) => { + println!("{:?}", e); + (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) { let project_root =