diff --git a/src/main.rs b/src/main.rs index 3029a98c..74da1ad2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,41 +73,14 @@ fn main() { let mut processor = vkprocessor::VkProcessor::new(&instance, &surface); processor.compile_kernel(String::from("simple-edge.compute")); - processor.load_buffers(String::from("funky-bird.jpg")); - processor.run_kernel(); - processor.read_image(); - processor.save_image(); - - + processor.compile_shaders(String::from("simple"), &surface); - let font = Font::from_file("resources/fonts/sansation.ttf").unwrap(); + processor.load_buffers(String::from("funky-bird.jpg")); - let mut window = RenderWindow::new( - (900, 900), - "Custom drawable", - Style::CLOSE, - &Default::default(), - ); let mut timer = Timer::new(); let mut input = Input::new(); - let xy = processor.xy; - - let mut workpieceloader = WorkpieceLoader::new(String::from("resources/images/funky-bird.jpg")); - workpieceloader.load_first_stage(processor.read_image()); - - let mut texture = Texture::from_file("resources/images/funky-bird.jpg").expect("Couldn't load image"); - - let mut workpiece = Workpiece::new(); - workpiece.render_sprite.set_texture(&mut texture, false); - - let mut slider = Slider::new(Vector2f::new(40.0, 40.0), None, &font); - - let mut selected_colors = Vec::new(); - - let mut button = button::Button::new(Vector2f::new(40.0,40.0), Vector2f::new(100.0,100.0), &font); - button.set_text("Text"); let step_size: f32 = 0.005; let mut elapsed_time: f32; @@ -117,54 +90,27 @@ fn main() { let mut mouse_xy = Vector2i::new(0,0); - while window.is_open() { - - while let Some(event) = window.poll_event() { - match event { - Event::Closed => return, - Event::KeyPressed { code, .. } => { - if code == Key::Escape { - return; - } - }, - Event::MouseButtonPressed { button, x, y} => { - let x = x as u32; - let y = y as u32; - mouse_xy = mouse::desktop_position(); - let r = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 0) as usize] as u8; - let g = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 1) as usize] as u8; - let b = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 2) as usize] as u8; - let a = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 3) as usize] as u8; - - selected_colors.push( - RectangleShape::with_size(Vector2f::new(30.0, 30.0)) - ); - - let mut x_position = 45.0 * selected_colors.len() as f32; - - selected_colors.last_mut().unwrap().set_position(Vector2f::new(x_position, 80.0)); - selected_colors.last_mut().unwrap().set_fill_color(&Color::rgba(r,g,b,a)); - }, - Event::MouseWheelScrolled { wheel, delta, x, y } => { - if delta > 0.0 { - workpiece.render_sprite.set_scale(workpiece.render_sprite.get_scale()*Vector2f::new(1.1,1.1)); - } else { - workpiece.render_sprite.set_scale(workpiece.render_sprite.get_scale()*Vector2f::new(0.9,0.9)); - } - }, - _ => {} - } - input.ingest(&event) - } + while let Some(p) = window.get_position() { + +// Event::MouseButtonPressed { button, x, y} => { +// let x = x as u32; +// let y = y as u32; +// mouse_xy = mouse::desktop_position(); +// let r = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 0) as usize] as u8; +// let g = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 1) as usize] as u8; +// let b = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 2) as usize] as u8; +// let a = processor.image_buffer[((processor.xy.0 * y + x) * 4 + 3) as usize] as u8; +// +// selected_colors.push( +// RectangleShape::with_size(Vector2f::new(30.0, 30.0)) +// ); +// +// let mut x_position = 45.0 * selected_colors.len() as f32; +// +// selected_colors.last_mut().unwrap().set_position(Vector2f::new(x_position, 80.0)); +// selected_colors.last_mut().unwrap().set_fill_color(&Color::rgba(r,g,b,a)); +// } - // Dragging by middle click - if input.is_mousebutton_held(Button::Middle) { - let delta = mouse_xy - mouse::desktop_position(); - mouse_xy = mouse::desktop_position(); - workpiece.render_sprite.set_position( - workpiece.render_sprite.position() - Vector2f::new(delta.x as f32, delta.y as f32) - ); - } elapsed_time = timer.elap_time(); delta_time = elapsed_time - current_time; @@ -178,18 +124,41 @@ fn main() { accumulator_time -= step_size; } - window.clear(&Color::BLACK); + processor.run_loop(&surface); + print!("adosfijqwe"); + + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + - window.draw(&workpiece.render_sprite); - window.draw(&slider); - for i in &selected_colors { - window.draw(i); - } - window.draw(&button); - window.display(); - } -} \ No newline at end of file diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index 4e39862c..e952e62f 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -30,6 +30,7 @@ use vulkano::descriptor::PipelineLayoutAbstract; use std::alloc::Layout; use vulkano::pipeline::viewport::Viewport; + #[derive(Default, Debug, Clone)] struct tVertex { position: [f32; 2] } @@ -92,7 +93,7 @@ unsafe impl SpecializationConstants for MySpecConstants { pub struct VkProcessor<'a> { pub instance: Arc, pub physical: PhysicalDevice<'a>, - pub pipeline: Option>, + pub pipeline: Option>, pub compute_pipeline: Option>>>, pub device: Arc, pub queues: QueuesIter, @@ -106,12 +107,11 @@ pub struct VkProcessor<'a> { pub xy: (u32, u32), pub render_pass: Option>, pub vertex_buffer: Option>, + pub dynamic_state: DynamicState, } impl<'a> VkProcessor<'a> { - pub fn new(instance : &'a Arc, surface : &'a Arc>) -> VkProcessor<'a> { - - + pub fn new(instance: &'a Arc, surface: &'a Arc>) -> VkProcessor<'a> { let physical = PhysicalDevice::enumerate(instance).next().unwrap(); let queue_family = physical.queue_families().find(|&q| { @@ -127,7 +127,6 @@ impl<'a> VkProcessor<'a> { physical.supported_features(), &device_ext, [(queue_family, 0.5)].iter().cloned()).unwrap(); - let queue = queues.next().unwrap(); VkProcessor { @@ -136,7 +135,7 @@ impl<'a> VkProcessor<'a> { pipeline: Option::None, compute_pipeline: Option::None, device: device, - queue: queues.next().unwrap(), + queue: queue, queues: queues, set: Option::None, image_buffer: Vec::new(), @@ -144,15 +143,14 @@ impl<'a> VkProcessor<'a> { settings_buffer: Option::None, swapchain: Option::None, images: Option::None, - xy: (0,0), + xy: (0, 0), render_pass: Option::None, vertex_buffer: Option::None, + dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None }, } - } pub fn compile_kernel(&mut self, filename: String) { - let project_root = std::env::current_dir() .expect("failed to get root directory"); @@ -192,35 +190,19 @@ impl<'a> VkProcessor<'a> { self.compute_pipeline = Some(compute_pipeline); } - pub fn compile_shaders(&mut self, filename: String, surface : &'a Arc>) { + pub fn compile_shaders(&mut self, filename: String, surface: &'a Arc>) { // Before we can draw on the surface, we have to create what is called a swapchain. Creating // a swapchain allocates the color buffers that will contain the image that will ultimately // be visible on the screen. These images are returned alongside with the swapchain. let (mut swapchain, images) = { - // Querying the capabilities of the surface. When we create the swapchain we can only - // pass values that are allowed by the capabilities. let capabilities = surface.capabilities(self.physical).unwrap(); - let usage = capabilities.supported_usage_flags; - - // The alpha mode indicates how the alpha value of the final image will behave. For example - // you can choose whether the window will be opaque or transparent. let alpha = capabilities.supported_composite_alpha.iter().next().unwrap(); - // Choosing the internal format that the images will have. let format = capabilities.supported_formats[0].0; - // The dimensions of the window, only used to initially setup the swapchain. - // NOTE: - // On some drivers the swapchain dimensions are specified by `caps.current_extent` and the - // swapchain size must use these dimensions. - // These dimensions are always the same as the window dimensions - // - // However other drivers dont specify a value i.e. `caps.current_extent` is `None` - // These drivers will allow anything but the only sensible value is the window dimensions. - // - // Because for both of these cases, the swapchain needs to be the window dimensions, we just use that. + // Set the swapchains window dimensions let initial_dimensions = if let Some(dimensions) = surface.window().get_inner_size() { // convert to physical pixels let dimensions: (u32, u32) = dimensions.to_physical(surface.window().get_hidpi_factor()).into(); @@ -230,9 +212,16 @@ impl<'a> VkProcessor<'a> { return; }; - // Please take a look at the docs for the meaning of the parameters we didn't mention. - Swapchain::new(self.device.clone(), surface.clone(), capabilities.min_image_count, format, - initial_dimensions, 1, usage, &self.queue, SurfaceTransform::Identity, alpha, + Swapchain::new(self.device.clone(), + surface.clone(), + capabilities.min_image_count, + format, + initial_dimensions, + 1, // Layers + usage, + &self.queue, + SurfaceTransform::Identity, + alpha, PresentMode::Fifo, true, None).unwrap() }; @@ -248,13 +237,11 @@ impl<'a> VkProcessor<'a> { let mut vertex_shader_path = project_root.clone(); vertex_shader_path.push(PathBuf::from("resources/shaders/")); - vertex_shader_path.push(PathBuf::from(filename.clone())); - vertex_shader_path.push(PathBuf::from(".vertex")); + vertex_shader_path.push(PathBuf::from(filename.clone() + ".vertex")); let mut fragment_shader_path = project_root.clone(); fragment_shader_path.push(PathBuf::from("resources/shaders/")); - fragment_shader_path.push(PathBuf::from(filename.clone())); - fragment_shader_path.push(PathBuf::from(".fragment")); + fragment_shader_path.push(PathBuf::from(filename.clone() + ".fragment")); let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap(); options.add_macro_definition("SETTING_POS_X", Some("0")); @@ -270,7 +257,7 @@ impl<'a> VkProcessor<'a> { sr::parse(&shader) .expect("failed to parse"); - let x1 : Arc = unsafe { + let x1: Arc = unsafe { vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &shader.fragment) }.unwrap(); @@ -278,20 +265,20 @@ impl<'a> VkProcessor<'a> { vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &shader.vertex) }.unwrap(); - let frag_entry_point : GraphicsEntryPoint = unsafe { + let frag_entry_point: GraphicsEntryPoint = unsafe { x1.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), vulkano_entry.frag_input, vulkano_entry.frag_output, vulkano_entry.frag_layout, - GraphicsShaderType::Fragment) + GraphicsShaderType::Fragment) }; - let vert_entry_point: GraphicsEntryPoint = unsafe { + let vert_entry_point: GraphicsEntryPoint = unsafe { x2.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), vulkano_entry.vert_input, vulkano_entry.vert_output, vulkano_entry.vert_layout, - GraphicsShaderType::Vertex) + GraphicsShaderType::Vertex) }; // The next step is to create a *render pass*, which is an object that describes where the @@ -325,6 +312,7 @@ impl<'a> VkProcessor<'a> { } ).unwrap()); + self.render_pass = Some(render_pass); // Before we draw we have to create what is called a pipeline. This is similar to an OpenGL // program, but much more specific. @@ -339,7 +327,7 @@ impl<'a> VkProcessor<'a> { .vertex_shader(vert_entry_point, MySpecConstants { my_integer_constant: 0, a_boolean: 0, - floating_point: 0.0 + floating_point: 0.0, }) // The content of the vertex buffer describes a list of triangles. .triangle_list() @@ -349,11 +337,11 @@ impl<'a> VkProcessor<'a> { .fragment_shader(frag_entry_point, MySpecConstants { my_integer_constant: 0, a_boolean: 0, - floating_point: 0.0 + floating_point: 0.0, }) // We have to indicate which subpass of which render pass this pipeline is going to be used // in. The pipeline will only be usable from this particular subpass. - .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) + .render_pass(Subpass::from(self.render_pass.clone().unwrap().clone(), 0).unwrap()) // Now that our builder is filled, we call `build()` to obtain an actual pipeline. .build(self.device.clone()) .unwrap(); @@ -363,78 +351,59 @@ impl<'a> VkProcessor<'a> { } - pub fn create_renderpass(&mut self) { - + // On resizes we have to recreate the swapchain + pub fn recreate_swapchain(&mut self, surface: &'a Arc>) { + let dimensions = if let Some(dimensions) = surface.window().get_inner_size() { + let dimensions: (u32, u32) = dimensions.to_physical(surface.window().get_hidpi_factor()).into(); + [dimensions.0, dimensions.1] + } else { + return; + }; + let (new_swapchain, new_images) = match self.swapchain.clone().unwrap().recreate_with_dimension(dimensions) { + Ok(r) => r, + // This error tends to happen when the user is manually resizing the window. + // Simply restarting the loop is the easiest way to fix this issue. + Err(SwapchainCreationError::UnsupportedDimensions) => panic!("Uh oh"), + Err(err) => panic!("{:?}", err) + }; + self.swapchain = Some(new_swapchain); + self.images = Some(new_images); } -// Onto the actual vulkan loop - pub fn run_loop(&mut self, surface : &'a Arc>){ - - // Dynamic viewports allow us to recreate just the viewport when the window is resized - // Otherwise we would have to recreate the whole pipeline. - let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None }; - - // The render pass we created above only describes the layout of our framebuffers. Before we - // can draw we also need to create the actual framebuffers. - // - // Since we need to draw to multiple images, we are going to create a different framebuffer for - // each image. - let mut framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), self.render_pass.clone().unwrap().clone(), &mut dynamic_state); - - // Initialization is finally finished! - - // In some situations, the swapchain will become invalid by itself. This includes for example - // when the window is resized (as the images of the swapchain will no longer match the - // window's) or, on Android, when the application went to the background and goes back to the - // foreground. - // - // In this situation, acquiring a swapchain image or presenting it will return an error. - // Rendering to an image of that swapchain will not produce any error, but may or may not work. - // To continue rendering, we need to recreate the swapchain by creating a new swapchain. - // Here, we remember that we need to do this for the next loop iteration. - 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 { + + pub fn run_loop(&mut self, surface: &'a Arc>) { + + let mut framebuffers = window_size_dependent_setup(&self.images.clone().unwrap().clone(), + self.render_pass.clone().unwrap().clone(), + &mut self.dynamic_state); + + 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 { - // Get the new dimensions of the window. - - let dimensions = if let Some(dimensions) = surface.window().get_inner_size() { - let dimensions: (u32, u32) = dimensions.to_physical(surface.window().get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - return; - }; - - let (new_swapchain, new_images) = match self.swapchain.clone().unwrap().recreate_with_dimension(dimensions) { - Ok(r) => r, - // This error tends to happen when the user is manually resizing the window. - // Simply restarting the loop is the easiest way to fix this issue. - Err(SwapchainCreationError::UnsupportedDimensions) => continue, - Err(err) => panic!("{:?}", err) - }; - - self.swapchain = Some(new_swapchain); - // Because framebuffers contains an Arc on the old swapchain, we need to - // recreate framebuffers as well. - framebuffers = window_size_dependent_setup(&new_images, self.render_pass.clone().unwrap().clone(), &mut dynamic_state); - + 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; } @@ -449,7 +418,8 @@ impl<'a> VkProcessor<'a> { Ok(r) => r, Err(AcquireError::OutOfDate) => { recreate_swapchain = true; - continue; + //continue; + panic!("Weird thing"); } Err(err) => panic!("{:?}", err) }; @@ -493,7 +463,7 @@ impl<'a> VkProcessor<'a> { // // 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(), &dynamic_state, v, (), ()) + .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 @@ -550,7 +520,7 @@ impl<'a> VkProcessor<'a> { // } // }); if done { return; } - } + //} } pub fn load_buffers(&mut self, image_filename: String) { @@ -620,9 +590,9 @@ impl<'a> VkProcessor<'a> { // Create the data descriptor set for our previously created shader pipeline let mut set = PersistentDescriptorSet::start(self.compute_pipeline.clone().unwrap().clone(), 0) - .add_buffer(write_buffer.clone()).unwrap() - .add_buffer(read_buffer.clone()).unwrap() - .add_buffer(settings_buffer.clone()).unwrap(); + .add_buffer(write_buffer.clone()).unwrap() + .add_buffer(read_buffer.clone()).unwrap() + .add_buffer(settings_buffer.clone()).unwrap(); self.set = Some(Arc::new(set.build().unwrap())); @@ -645,72 +615,72 @@ impl<'a> VkProcessor<'a> { self.vertex_buffer = Some(vertex_buffer); } - pub fn run_kernel(&mut self) { - - println!("Running Kernel..."); - - // The command buffer I think pretty much serves to define what runs where for how many times - 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() - .build().unwrap(); - - // Create a future for running the command buffer and then just fence it - let future = sync::now(self.device.clone()) - .then_execute(self.queue.clone(), command_buffer).unwrap() - .then_signal_fence_and_flush().unwrap(); - - // I think this is redundant and returns immediately - future.wait(None).unwrap(); - println!("Done running kernel"); - } - - pub fn read_image(&self) -> Vec { - - // The buffer is sync'd so we can just read straight from the handle - let mut data_buffer_content = self.img_buffers.get(0).unwrap().read().unwrap(); - - println!("Reading output"); - - let mut image_buffer = Vec::new(); - - for y in 0..self.xy.1 { - for x in 0..self.xy.0 { - - let r = data_buffer_content[((self.xy.0 * y + x) * 4 + 0) as usize] as u8; - let g = data_buffer_content[((self.xy.0 * y + x) * 4 + 1) as usize] as u8; - let b = data_buffer_content[((self.xy.0 * y + x) * 4 + 2) as usize] as u8; - let a = data_buffer_content[((self.xy.0 * y + x) * 4 + 3) as usize] as u8; - - image_buffer.push(r); - image_buffer.push(g); - image_buffer.push(b); - image_buffer.push(a); - } - } - - image_buffer - } - - pub fn save_image(&self) { - println!("Saving output"); - - let img_data = self.read_image(); - - let img = ImageBuffer::from_fn(self.xy.0, self.xy.1, |x, y| { - - let r = img_data[((self.xy.0 * y + x) * 4 + 0) as usize] as u8; - let g = img_data[((self.xy.0 * y + x) * 4 + 1) as usize] as u8; - let b = img_data[((self.xy.0 * y + x) * 4 + 2) as usize] as u8; - let a = img_data[((self.xy.0 * y + x) * 4 + 3) as usize] as u8; - - image::Rgba([r, g, b, a]) - }); - - img.save(format!("output/{}.png", SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs())); - } +// pub fn run_kernel(&mut self) { +// +// println!("Running Kernel..."); +// +// // The command buffer I think pretty much serves to define what runs where for how many times +// 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() +// .build().unwrap(); +// +// // Create a future for running the command buffer and then just fence it +// let future = sync::now(self.device.clone()) +// .then_execute(self.queue.clone(), command_buffer).unwrap() +// .then_signal_fence_and_flush().unwrap(); +// +// // I think this is redundant and returns immediately +// future.wait(None).unwrap(); +// println!("Done running kernel"); +// } + +// pub fn read_image(&self) -> Vec { +// +// // The buffer is sync'd so we can just read straight from the handle +// let mut data_buffer_content = self.img_buffers.get(0).unwrap().read().unwrap(); +// +// println!("Reading output"); +// +// let mut image_buffer = Vec::new(); +// +// for y in 0..self.xy.1 { +// for x in 0..self.xy.0 { +// +// let r = data_buffer_content[((self.xy.0 * y + x) * 4 + 0) as usize] as u8; +// let g = data_buffer_content[((self.xy.0 * y + x) * 4 + 1) as usize] as u8; +// let b = data_buffer_content[((self.xy.0 * y + x) * 4 + 2) as usize] as u8; +// let a = data_buffer_content[((self.xy.0 * y + x) * 4 + 3) as usize] as u8; +// +// image_buffer.push(r); +// image_buffer.push(g); +// image_buffer.push(b); +// image_buffer.push(a); +// } +// } +// +// image_buffer +// } + +// pub fn save_image(&self) { +// println!("Saving output"); +// +// let img_data = self.read_image(); +// +// let img = ImageBuffer::from_fn(self.xy.0, self.xy.1, |x, y| { +// +// let r = img_data[((self.xy.0 * y + x) * 4 + 0) as usize] as u8; +// let g = img_data[((self.xy.0 * y + x) * 4 + 1) as usize] as u8; +// let b = img_data[((self.xy.0 * y + x) * 4 + 2) as usize] as u8; +// let a = img_data[((self.xy.0 * y + x) * 4 + 3) as usize] as u8; +// +// image::Rgba([r, g, b, a]) +// }); +// +// img.save(format!("output/{}.png", SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs())); +// } }