diff --git a/Cargo.toml b/Cargo.toml index b810d908..27366eb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,5 @@ shaderc = "0.5.0" #shade_runner = {version = "0.1.1", git = "https://github.com/MitchellHansen/shade_runner"} shade_runner = {path = "../shade_runner"} winit = "0.19.1" +#criterion = "0.3.0" +hprof = "0.1.3" \ No newline at end of file diff --git a/resources/shaders/color-passthrough.fragment b/resources/shaders/color-passthrough.fragment index f15e5385..28779dd1 100644 --- a/resources/shaders/color-passthrough.fragment +++ b/resources/shaders/color-passthrough.fragment @@ -1,9 +1,11 @@ #version 450 + +// These come in from the previous shader (vertex) layout(location = 0) in vec4 out_color; +// This goes out to the bound image in window_size_dependent setup layout(location = 0) out vec4 f_color; - void main() { f_color = out_color; } diff --git a/resources/shaders/color-passthrough.vertex b/resources/shaders/color-passthrough.vertex index feeaab0e..ed3b6541 100644 --- a/resources/shaders/color-passthrough.vertex +++ b/resources/shaders/color-passthrough.vertex @@ -1,7 +1,10 @@ #version 450 + +// These come in from the vertex definition layout(location = 0) in vec2 position; layout(location = 1) in vec4 color; +// These are made up in the shader themselves layout(location = 0) out vec4 out_color; void main() { diff --git a/resources/shaders/simple-edge.compute b/resources/shaders/simple-edge.compute index add83ad2..48ed163e 100644 --- a/resources/shaders/simple-edge.compute +++ b/resources/shaders/simple-edge.compute @@ -1,6 +1,6 @@ #version 450 -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(set = 0, binding = 0) buffer wData { int buf[]; @@ -58,7 +58,6 @@ void main() { p.z = 255; } else { - //p.w = 125; } @@ -69,10 +68,6 @@ void main() { } - - - - // Just gonna keep this around // read_buffer.buf[idx] = (read_buffer.buf[idx] & (~0x000000FF) ) | (p.x); // read_buffer.buf[idx] = (read_buffer.buf[idx] & (~0x0000FF00) ) | (p.y << 8); diff --git a/resources/shaders/simple_texture.fragment b/resources/shaders/simple_texture.fragment index e8ead073..ee552946 100644 --- a/resources/shaders/simple_texture.fragment +++ b/resources/shaders/simple_texture.fragment @@ -1,8 +1,14 @@ #version 450 +// SIMPLE TEXTURE : FRAGMENT SHADER + +// These come in from the previous shader (vertex) layout(location = 0) in vec2 tex_coords; +// This goes out to the bound image in window_size_dependent setup layout(location = 0) out vec4 f_color; +// This is bound by the descriptor set +// Currently handled by the individual buffer and are 1:1 layout(set = 0, binding = 0) uniform sampler2D tex; void main() { diff --git a/resources/shaders/simple_texture.vertex b/resources/shaders/simple_texture.vertex index 5f5af841..10862635 100644 --- a/resources/shaders/simple_texture.vertex +++ b/resources/shaders/simple_texture.vertex @@ -1,10 +1,16 @@ #version 450 +// SIMPLE TEXTURE : VERTEX SHADER + +// These come in from the vertex definition +// TODO : Need to add texture coordinate attribute so I can single VBO all these sumbitches layout(location = 0) in vec2 position; +// These are made up in the shader themselves layout(location = 0) out vec2 tex_coords; void main() { + gl_Position = vec4(position, 0.0, 1.0); tex_coords = position; } diff --git a/src/canvas.rs b/src/canvas.rs index d6f79370..57eb8f0b 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -22,46 +22,26 @@ use vulkano::descriptor::descriptor::DescriptorDescTy::TexelBuffer; use crate::canvas_frame::CanvasFrame; use std::hash::Hash; use crate::canvas_shader::CanvasShader; - -// Canvas is the accumulator of Sprites for drawing - -// Needs to know: -// textured? -// colored? -// vertices - +use crate::canvas_buffer::{CanvasImage, CanvasTexture}; /* - If it is textured. It needs to be rendered with the texture shader which requires a separate graphics pipeline. Might as well have a new render pass as well. - - So framebuffer is tied to the swapchains images as well as the renderpass it appears that renderpass is tied to the individual shader - - */ -// I want to be able to draw 2d sprites. - -// These sprites might be textured or a single color - -// All of the single colors will be grouped into one batch using colored vertices. -// The rest will be grouped by their texture and run individually - +/// Vertex trait for Drawable Vertices. pub trait Vertex { fn position(&self) -> (f32, f32) { (0.0, 0.0) } - fn color(&self) -> Option<(f32, f32, f32, f32)> { Some((0., 0., 0., 0.)) } } - impl Vertex for ColoredVertex2D { fn position(&self) -> (f32, f32) { (0.0, 0.0) @@ -72,6 +52,8 @@ impl Vertex for ColoredVertex2D { } } +/// A drawable object can be passed into a CanvasFrame to be rendered +/// Allows Texture or Image drawing via their handles pub trait Drawable { fn get_vertices(&self) -> Vec<(f32, f32)>; fn get_color(&self) -> (f32, f32, f32, f32); @@ -79,7 +61,7 @@ pub trait Drawable { fn get_image_handle(&self) -> Option>; } -// Need three types of shaders. Solid, Textured, Image +/// Legacy ShaderType enum for single type shaders. #[derive(PartialEq, Eq, Hash, Clone)] pub enum ShaderType { SOLID = 0, @@ -87,64 +69,18 @@ pub enum ShaderType { IMAGE = 2, } - +/// Typed wrapper for a u32 texture handle (index id) #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasTextureHandle { pub handle: u32 } +/// Typed wrapper for a u32 image handle (index id) #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasImageHandle { pub handle: u32 } -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct CanvasShaderHandle { - pub handle: u32 -} - -#[derive(Clone)] -pub struct CanvasTexture { - handle: Arc, - buffer: Arc>, - name: String, - size: (u32, u32), -} - -impl CanvasTexture { - fn get_descriptor_set(&self, - shader: Arc, - sampler: Arc) -> Box { - let o: Box = Box::new( - PersistentDescriptorSet::start( - shader.clone().get_pipeline().clone(), 0, - ) - .add_sampled_image(self.buffer.clone(), sampler.clone()).unwrap() - .build().unwrap()); - o - } -} - -#[derive(Clone)] -pub struct CanvasImage { - handle: Arc, - buffer: Arc, - size: (u32, u32), -} - -impl CanvasImage { - fn get_descriptor_set(&mut self, shader: Arc) - -> Box { - let o: Box = Box::new( - PersistentDescriptorSet::start( - shader.clone().get_pipeline().clone(), 0, - ) - .add_image(self.buffer.clone()).unwrap() - .build().unwrap()); - o - } -} - #[derive(Clone)] pub struct CanvasState { dynamic_state: DynamicState, @@ -200,9 +136,6 @@ impl CanvasState { physical: PhysicalDevice, capabilities: Capabilities) -> CanvasState { - let solid_color_kernel = String::from("color-passthrough"); - let texture_kernel = String::from("simple_texture"); - CanvasState { dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None }, sampler: Sampler::new(device.clone(), Filter::Linear, Filter::Linear, @@ -210,20 +143,7 @@ impl CanvasState { SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(), image_buffers: vec![], texture_buffers: vec![], - shader_buffers: HashMap::from_iter(vec![ - (solid_color_kernel.clone(), Arc::new(CanvasShader::new_colored(solid_color_kernel.clone(), - capabilities.clone(), - queue.clone(), - physical.clone(), - device.clone())) - ), - (texture_kernel.clone(), Arc::new(CanvasShader::new_textured(texture_kernel.clone(), - capabilities.clone(), - queue.clone(), - physical.clone(), - device.clone())) - ), - ]), + shader_buffers: HashMap::from_iter(vec![]), colored_drawables: vec![], colored_vertex_buffer: vec![], @@ -238,8 +158,7 @@ impl CanvasState { } pub fn create_image(&mut self, dimensions: (u32, u32), usage: ImageUsage) -> Arc { - - let handle = Arc::new(CanvasImageHandle { handle: self.image_buffers.len() as u32}); + let handle = Arc::new(CanvasImageHandle { handle: self.image_buffers.len() as u32 }); let image = CanvasImage { handle: handle.clone(), @@ -322,9 +241,24 @@ impl CanvasState { Some(handle) } - pub fn get_texture_handle(&self, texture_name: String) - -> Option> { + /// Load and Compile a shader with the filename at resources/shaders + /// Takes physical and capabilities as we don't store that in Canvas + pub fn load_shader(&mut self, + filename: String, + physical: PhysicalDevice, + capabilities: Capabilities) { + + self.shader_buffers.insert(filename.clone(), + Arc::new(CanvasShader::new_colored(filename.clone(), + capabilities.clone(), + self.queue.clone(), + physical.clone(), + self.device.clone()))); + } + /// Using the texture name, iterates through the stored textures and matches by the name + pub fn get_texture_handle(&self, texture_name: String) + -> Option> { for i in self.texture_buffers.clone() { if i.name == texture_name { return Some(i.handle.clone()); @@ -333,9 +267,9 @@ impl CanvasState { None } + /// Using the texture handle, grab the stored texture and return the buffer pub fn get_texture(&self, texture_handle: Arc) - -> Arc> { - + -> Arc> { let handle = texture_handle.handle as usize; if let Some(i) = self.texture_buffers.get(handle) { @@ -345,53 +279,64 @@ impl CanvasState { } } - // After done using this, need to call allocated vertex buffers + /// Scrape all the values from the CanvasFrame and then allocate the vertex buffers pub fn draw(&mut self, canvas_frame: CanvasFrame) { self.textured_drawables = canvas_frame.textured_drawables; self.colored_drawables = canvas_frame.colored_drawables; self.image_drawables = canvas_frame.image_drawables; - self.allocate_vertex_buffers(self.device.clone()); + self.allocate_vertex_buffers(); } - fn allocate_vertex_buffers(&mut self, device: Arc) { - self.colored_vertex_buffer.clear(); - self.textured_vertex_buffer.clear(); - self.image_vertex_buffer.clear(); - - //TODO should probably use cpu accessible buffer instead of recreating immutes each frame - /* - CpuAccessibleBuffer::from_iter( + /// draw(canvas_fame) stored all the intermediate information, this function + /// allocates the vertex buffers using that information + fn allocate_vertex_buffers(&mut self) { - device.clone(), - BufferUsage::vertex_buffer(), - self.colored_drawables.iter().cloned(), - ).unwrap().0; - */ - - self.colored_vertex_buffer.push( - ImmutableBuffer::from_iter( - self.colored_drawables.iter().cloned(), - BufferUsage::vertex_buffer(), - self.queue.clone(), - ).unwrap().0 - ); - - for (k, v) in self.textured_drawables.drain() { - println!("{:?}", v.len()); - self.textured_vertex_buffer.insert( - k.clone(), + self.colored_vertex_buffer.clear(); + { + let g = hprof::enter("Colored Vertex Buffer"); + self.colored_vertex_buffer.push( ImmutableBuffer::from_iter( - v.first().unwrap().iter().cloned(), + self.colored_drawables.iter().cloned(), BufferUsage::vertex_buffer(), self.queue.clone(), - ).unwrap().0, + ).unwrap().0 ); } + + self.textured_vertex_buffer.clear(); + { + let g = hprof::enter("Textured Vertex Buffer"); + for (k, v) in self.textured_drawables.drain() { + self.textured_vertex_buffer.insert( + k.clone(), + ImmutableBuffer::from_iter( + v.first().unwrap().iter().cloned(), + BufferUsage::vertex_buffer(), + self.queue.clone(), + ).unwrap().0, + ); + } + } + + self.image_vertex_buffer.clear(); + { + let g = hprof::enter("Image Vertex Buffer"); + for (k, v) in self.image_drawables.drain() { + self.image_vertex_buffer.insert( + k.clone(), + ImmutableBuffer::from_iter( + v.first().unwrap().iter().cloned(), + BufferUsage::vertex_buffer(), + self.queue.clone(), + ).unwrap().0, + ); + } + } } + /// Builds the descriptor set for solid colors using the input kernel (needs to support solid colors) fn get_solid_color_descriptor_set(&self, kernel: Arc) -> Box { - let o: Box = Box::new( PersistentDescriptorSet::start( kernel.clone().get_pipeline().clone(), 0, @@ -399,6 +344,7 @@ impl CanvasState { o } + /// Pushes the draw commands s pub fn draw_commands(&self, mut command_buffer: AutoCommandBufferBuilder, framebuffers: Vec>, @@ -414,47 +360,55 @@ impl CanvasState { // Solid colors let mut shader = self.shader_buffers.get("color-passthrough").unwrap().clone(); - command_buffer = command_buffer.draw( - shader.get_pipeline().clone(), - &self.dynamic_state.clone(), - self.colored_vertex_buffer.clone(), - (), (), - ).unwrap(); - + // This looks a little weird as colored_vertex_buffer is a vec of GPU allocated vecs. + // But we can pass in multiple vertex buffers + if !self.colored_vertex_buffer.is_empty() { + command_buffer = command_buffer.draw( + shader.get_pipeline().clone(), + &self.dynamic_state.clone(), + self.colored_vertex_buffer.clone(), + (), (), + ).unwrap(); + } - // Images + // Textures let mut shader = self.shader_buffers.get("simple_texture").unwrap().clone(); + if !self.textured_vertex_buffer.is_empty() { + let handle = self.get_texture_handle(String::from("funky-bird.jpg")).unwrap().clone(); + + // TODO : BAD BAD BAD. SELECTS FIRST TEXTURE ONLY!!!!!!!!!!!! + let descriptor_set = self.texture_buffers.first().clone().unwrap().clone() + .get_descriptor_set(shader.clone(), self.sampler.clone()); - let handle = self.get_texture_handle(String::from("funky-bird.jpg")).unwrap().clone(); + let vertex_buffer = self.textured_vertex_buffer.get(&handle).unwrap().clone(); - let descriptor_set = self.texture_buffers.first().clone().unwrap().clone() - .get_descriptor_set(shader.clone(), self.sampler.clone()); + command_buffer = command_buffer.draw( + shader.get_pipeline().clone(), + &self.dynamic_state.clone(), vec![vertex_buffer], + vec![descriptor_set], (), + ).unwrap(); + } - let vertex_buffer = self.textured_vertex_buffer.get(&handle).unwrap().clone(); - println!("{:?}", self.texture_buffers.len()); - command_buffer = command_buffer.draw( - shader.get_pipeline().clone(), - &self.dynamic_state.clone(), vec![vertex_buffer], - vec![descriptor_set], () - ).unwrap(); + let mut shader = self.shader_buffers.get("simple-image").unwrap().clone(); - /*for (shader_type, kernel) in self.shader_kernels.clone().iter() { - match shader_type { - ShaderType::SOLID => { + if !self.image_vertex_buffer.is_empty() { - } - ShaderType::TEXTURED => { - command_buffer = command_buffer.draw( - kernel.clone().get_pipeline().clone(), - &dynamic_state.clone(), self.textured_vertex_buffer.clone(), - vec![self.get_textured_descriptor_set(String::from("funky-bird.jpg"))], () - ).unwrap(); - } - ShaderType::IMAGE => {} - } - }*/ + let handle = self.get_texture_handle(String::from("funky-bird.jpg")).unwrap().clone(); + + // TODO : BAD BAD BAD. SELECTS FIRST TEXTURE ONLY!!!!!!!!!!!! + let descriptor_set = self.texture_buffers.first().clone().unwrap().clone() + .get_descriptor_set(shader.clone(), self.sampler.clone()); + + let vertex_buffer = self.textured_vertex_buffer.get(&handle).unwrap().clone(); + + command_buffer = command_buffer.draw( + shader.get_pipeline().clone(), + &self.dynamic_state.clone(), vec![vertex_buffer], + vec![descriptor_set], (), + ).unwrap(); + } command_buffer .end_render_pass() diff --git a/src/canvas_buffer.rs b/src/canvas_buffer.rs new file mode 100644 index 00000000..99fc1536 --- /dev/null +++ b/src/canvas_buffer.rs @@ -0,0 +1,50 @@ +use crate::canvas::{CanvasTextureHandle, CanvasImageHandle}; +use vulkano::image::{ImmutableImage, AttachmentImage}; +use std::sync::Arc; +use vulkano::format::Format; +use crate::canvas_shader::CanvasShader; +use vulkano::sampler::Sampler; +use vulkano::descriptor::DescriptorSet; +use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; + +#[derive(Clone)] +pub struct CanvasTexture { + pub(crate) handle: Arc, + pub(crate) buffer: Arc>, + pub(crate) name: String, + pub(crate) size: (u32, u32), +} + +impl CanvasTexture { + pub fn get_descriptor_set(&self, + shader: Arc, + sampler: Arc) -> Box { + let o: Box = Box::new( + PersistentDescriptorSet::start( + shader.clone().get_pipeline().clone(), 0, + ) + .add_sampled_image(self.buffer.clone(), sampler.clone()).unwrap() + .build().unwrap()); + o + } +} + +#[derive(Clone)] +pub struct CanvasImage { + pub(crate) handle: Arc, + pub(crate) buffer: Arc, + pub(crate) size: (u32, u32), +} + +impl CanvasImage { + pub fn get_descriptor_set(&mut self, shader: Arc) + -> Box { + let o: Box = Box::new( + PersistentDescriptorSet::start( + shader.clone().get_pipeline().clone(), 0, + ) + .add_image(self.buffer.clone()).unwrap() + .build().unwrap()); + o + } +} \ No newline at end of file diff --git a/src/canvas_frame.rs b/src/canvas_frame.rs index aa15dd12..2bcf9635 100644 --- a/src/canvas_frame.rs +++ b/src/canvas_frame.rs @@ -1,7 +1,7 @@ use crate::vertex_2d::{ColoredVertex2D, Vertex2D}; use std::sync::Arc; use std::collections::HashMap; -use crate::canvas::{Drawable, CanvasTextureHandle, CanvasImage, CanvasImageHandle}; +use crate::canvas::{Drawable, CanvasTextureHandle, CanvasImageHandle}; pub struct CanvasFrame { pub colored_drawables: Vec, diff --git a/src/canvas_shader.rs b/src/canvas_shader.rs index 9ff3475c..2073866e 100644 --- a/src/canvas_shader.rs +++ b/src/canvas_shader.rs @@ -10,12 +10,13 @@ use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, Specialization use vulkano::swapchain::{Capabilities}; use crate::vertex_2d::{ColoredVertex2D, Vertex2D}; -/* - -CanvasShader holds the pipeline and render pass for the inputted shader source - -*/ +/// Typed wrapper for a u32 shader handle (index id) +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +pub struct CanvasShaderHandle { + pub handle: u32 +} +/// CanvasShader holds the pipeline and render pass for the input shader source #[derive(Clone)] pub struct CanvasShader { @@ -27,6 +28,8 @@ pub struct CanvasShader { impl CanvasShader { + /// Takes the filename of a .vertex .fragment shader combo in resources/shaders/ + /// Returns pathbuffer of that vertex and fragment shader fn get_path(filename: String) -> (PathBuf, PathBuf) { let project_root = @@ -47,10 +50,13 @@ impl CanvasShader { (vertex_shader_path, fragment_shader_path) } + /// Clone and returns the compiled graphics pipeline pub fn get_pipeline(&self) -> Arc { self.graphics_pipeline.clone().unwrap() } + /// Create a new `Colored` shader. Which just means that it uses ColoredVertex2D's + /// This will explode when the shader does not want to compile pub fn new_colored(filename: String, capabilities: Capabilities, queue: Arc, @@ -168,6 +174,8 @@ impl CanvasShader { } } + /// Create a new `Textured` shader. Which just means that it uses plain Vertex2D's + /// This will explode when the shader does not want to compile pub fn new_textured(filename: String, capabilities: Capabilities, queue: Arc, @@ -289,7 +297,7 @@ impl CanvasShader { #[repr(C)] #[derive(Default, Debug, Clone)] -// TODO: This needs to be duplicated and moved into their respective containers shaderkenrels copute +/// Specialization constants which can be passed to the shader. Pretty much placeholder ATM struct ShaderSpecializationConstants { first_constant: i32, second_constant: u32, diff --git a/src/compu_state.rs b/src/compu_state.rs index d1be3203..fae5798c 100644 --- a/src/compu_state.rs +++ b/src/compu_state.rs @@ -1,7 +1,7 @@ use std::ffi::CStr; use vulkano::buffer::{CpuAccessibleBuffer, BufferUsage}; use std::sync::Arc; -use crate::canvas::{Drawable, CanvasState, CanvasImageHandle, CanvasImage, CanvasTextureHandle}; +use crate::canvas::{Drawable, CanvasState, CanvasImageHandle, CanvasTextureHandle}; use vulkano::framebuffer::RenderPassAbstract; use vulkano::pipeline::{GraphicsPipelineAbstract, ComputePipeline}; use vulkano::device::Device; @@ -104,7 +104,7 @@ impl CompuState { let size = buffer.get_size(); command_buffer = command_buffer - .dispatch([size.0,size.1,1], p, d, ()).unwrap() + .dispatch([size.0/8,size.1/8,1], p, d, ()).unwrap() } // i = (Buffer, Image, Kernel) @@ -126,8 +126,10 @@ impl CompuState { panic!("Buffer sizes not the same"); } + let size = buffer.get_size(); + command_buffer = command_buffer - .dispatch([100,100,1], p, d, ()).unwrap() + .dispatch([size.0,size.1,1], p, d, ()).unwrap() .copy_buffer_to_image(buffer.get_input_buffer(), image).unwrap(); } diff --git a/src/main.rs b/src/main.rs index 0d37a8fb..b9140204 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate nalgebra as na; extern crate rand; extern crate sfml; extern crate time; +extern crate hprof; use sfml::system::*; use vulkano::sync; @@ -27,23 +28,25 @@ use crate::compu_buffer::CompuBuffers; use crate::util::load_raw; use crate::canvas_frame::CanvasFrame; -mod util; -mod timer; -mod input; -mod vkprocessor; -mod vertex_2d; -mod vertex_3d; -mod sprite; +pub mod util; +pub mod timer; +pub mod input; +pub mod vkprocessor; +pub mod vertex_2d; +pub mod vertex_3d; +pub mod sprite; -mod canvas; -mod canvas_frame; -mod canvas_shader; +pub mod canvas; +pub mod canvas_frame; +pub mod canvas_shader; +pub mod canvas_buffer; + +pub mod compu_state; +pub mod compu_frame; +pub mod compu_sprite; +pub mod compu_kernel; +pub mod compu_buffer; -mod compu_state; -mod compu_frame; -mod compu_sprite; -mod compu_kernel; -mod compu_buffer; /* @@ -53,7 +56,13 @@ Canvas works, but I want to use CPU accessible buffer instead of immutable buffe I think it would be faster if we reuse fewer oversized buffers than vis versa */ -fn main() { + +/// Main Entry +pub fn main() { + + hprof::start_frame(); + + let q1 = hprof::enter("setup"); let instance = { let extensions = vulkano_win::required_extensions(); @@ -67,11 +76,16 @@ fn main() { let mut window = surface.window(); let mut processor = vkprocessor::VkProcessor::new(&instance, &surface); - processor.create_swapchain(&surface); + { + let g = hprof::enter("vulkan preload"); + processor.create_swapchain(&surface); + + processor.preload_kernels(); + processor.preload_shaders(); + processor.preload_textures(); + } - processor.preload_kernels(); - processor.preload_shaders(); - processor.preload_textures(); + let q2 = hprof::enter("Game Objects"); let mut timer = Timer::new(); let mut frame_future = Box::new(sync::now(processor.device.clone())) as Box; @@ -84,10 +98,6 @@ fn main() { let mut mouse_xy = Vector2i::new(0,0); - - - - let sprite = Sprite::new_with_color((0.,0.), (0.1,0.1), (1.,0.,0.,1.)); let sprite2 = Sprite::new_with_color((-1.,-0.5), (0.1,0.1), (0.,1.,0.,1.)); @@ -105,9 +115,14 @@ fn main() { let sprite3 = Sprite::new_with_texture((0.3, 0.5), (0.1,0.1), handle.clone()); + drop(q2); + drop(q1); - while let Some(p) = window.get_position() { + let l = hprof::enter("Loop"); + + let mut exit = false; + while let Some(p) = window.get_position() { elapsed_time = timer.elap_time(); delta_time = elapsed_time - current_time; current_time = elapsed_time; @@ -120,9 +135,7 @@ fn main() { accumulator_time -= step_size; } - println!("{}", delta_time); - - let mut exit = false; + // println!("{}", delta_time); events_loop.poll_events(|event| { match event { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => @@ -133,11 +146,10 @@ fn main() { processor.recreate_swapchain(&surface); }, Event::DeviceEvent { event: DeviceEvent::Key(keyboard_input), .. } => { - match keyboard_input.virtual_keycode.unwrap() { VirtualKeyCode::A => { if keyboard_input.state == ElementState::Pressed { - // processor.save_edges_image(); + // processor.save_edges_image(); } } _ => () @@ -151,7 +163,7 @@ fn main() { }); if exit { - return; + break; } let mut compu_frame = CompuFrame::new(); @@ -162,12 +174,20 @@ fn main() { canvas.draw(&sprite); canvas.draw(&sprite2); canvas.draw(&sprite3); - canvas.draw(&compu_sprite1); - - (frame_future) = processor.run(&surface, frame_future, - canvas, - compu_frame); + //canvas.draw(&compu_sprite1); + { + let g = hprof::enter("Run"); + processor.run(&surface, + //frame_future, + canvas, + compu_frame); + } } + + drop(l); + + hprof::end_frame(); + hprof::profiler().print_timing(); } diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index df046fca..2aad7ed7 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -1,22 +1,26 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use vulkano::device::{Device, DeviceExtensions, QueuesIter, Queue}; use vulkano::instance::{Instance, PhysicalDevice}; -use vulkano::sync::{GpuFuture, FlushError}; +use vulkano::sync::{GpuFuture, FlushError, NowFuture}; +use vulkano::sync::now; use vulkano::sync; use std::sync::Arc; use vulkano::swapchain::{Swapchain, PresentMode, SurfaceTransform, Surface, SwapchainCreationError, AcquireError, Capabilities}; use vulkano::image::swapchain::SwapchainImage; -use winit::{Window}; +use winit::Window; use crate::compu_state::CompuState; use vulkano::image::ImageUsage; use crate::compu_frame::CompuFrame; -use crate::canvas::{CanvasState, CanvasTextureHandle, CanvasShaderHandle, CanvasImageHandle}; +use crate::canvas::{CanvasState, CanvasTextureHandle, CanvasImageHandle}; use crate::canvas_frame::CanvasFrame; use crate::compu_kernel::{CompuKernel, CompuKernelHandle}; use crate::compu_buffer::{CompuBuffers, CompuBufferHandle}; +use std::time::Duration; +use crate::canvas_shader::CanvasShaderHandle; +/// VKProcessor holds the vulkan instance information, the swapchain, and the compute and canvas states +/// pub struct VkProcessor<'a> { - // Vulkan state fields pub instance: Arc, pub physical: PhysicalDevice<'a>, @@ -39,7 +43,10 @@ pub struct VkProcessor<'a> { impl<'a> VkProcessor<'a> { + /// Creates a new VkProcessor from an instance and surface + /// This includes the physical device, queues, compute and canvas state 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| { @@ -75,6 +82,7 @@ impl<'a> VkProcessor<'a> { } } + /// Using the surface, we calculate the surface capabilities and create the swapchain and swapchain images pub fn create_swapchain(&mut self, surface: &'a Arc>) { let (mut swapchain, images) = { let capabilities = surface.capabilities(self.physical).unwrap(); @@ -103,14 +111,14 @@ impl<'a> VkProcessor<'a> { &self.queue, SurfaceTransform::Identity, alpha, - PresentMode::Fifo, true, None).unwrap() + PresentMode::Immediate, true, None).unwrap() }; self.swapchain = Some(swapchain); self.swapchain_images = Some(images); } - // On resizes we have to recreate the swapchain + /// On screen resizes, the swapchain and images must be recreated 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(); @@ -131,20 +139,27 @@ impl<'a> VkProcessor<'a> { self.swapchain_images = Some(new_images); } + /// A hardcoded list of textures which can be preloaded from this function pub fn preload_textures(&mut self) { self.canvas.load_texture(String::from("funky-bird.jpg")); self.canvas.load_texture(String::from("button.png")); self.canvas.load_texture(String::from("background.jpg")); self.canvas.load_texture(String::from("test2.png")); } + + /// A hardcoded list of kernels which can be preloaded from this function pub fn preload_kernels(&mut self) { self.compute_state.new_kernel(String::from("simple-homogenize.compute"), self.device.clone()); self.compute_state.new_kernel(String::from("simple-edge.compute"), self.device.clone()); } - pub fn preload_shaders(&mut self) { + /// A hardcoded list of shaders which can be proloaded from this function + pub fn preload_shaders(&mut self) { + self.canvas.load_shader(String::from("color-passthrough"), self.physical.clone(), self.capabilities.clone()); + self.canvas.load_shader(String::from("simple_texture"), self.physical.clone(), self.capabilities.clone()); } + pub fn get_texture_handle(&self, texture_name: String) -> Option> { self.canvas.get_texture_handle(texture_name) } @@ -178,22 +193,19 @@ impl<'a> VkProcessor<'a> { pub fn run(&mut self, surface: &'a Arc>, - mut frame_future: Box, canvas_frame: CanvasFrame, compute_frame: CompuFrame, - ) - -> Box { + ) { - // take the canvas frame and create the vertex buffers - // TODO: This performs gpu buffer creation. Shouldn't be in hotpath - self.canvas.draw(canvas_frame); + { + let g = hprof::enter("Waiting at queue"); + self.queue.wait(); + } + let g = hprof::enter("Frame buffer, future, swapchain recreate"); let mut framebuffers = self.canvas.window_size_dependent_setup(&self.swapchain_images.clone().unwrap().clone()); - // 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 self.swapchain_recreate_needed { @@ -205,44 +217,69 @@ impl<'a> VkProcessor<'a> { // 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) => { - self.swapchain_recreate_needed = true; - return Box::new(sync::now(self.device.clone())) as Box<_>; - } - Err(err) => panic!("{:?}", err) - }; + let (image_num, acquire_future) = + match vulkano::swapchain::acquire_next_image( + self.swapchain.clone().unwrap().clone(), + None, + ) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + self.swapchain_recreate_needed = true; + return; + } + Err(err) => panic!("{:?}", err) + }; + + drop(g); + + { + let g = hprof::enter("Canvas creates GPU buffers"); + // take the canvas frame and create the vertex buffers + // TODO: This performs gpu buffer creation. Shouldn't be in hotpath?? + self.canvas.draw(canvas_frame); + } let mut command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(self.device.clone(), self.queue.family()).unwrap(); + let g = hprof::enter("Push compute commands to command buffer"); // Add the compute commands let mut command_buffer = self.compute_state.compute_commands(compute_frame, command_buffer, &self.canvas); + drop(g); + let g = hprof::enter("Push draw commands to command buffer"); // Add the draw commands let mut command_buffer = self.canvas.draw_commands(command_buffer, framebuffers, image_num); // And build let command_buffer = command_buffer.build().unwrap(); + drop(g); // 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) => { - self.swapchain_recreate_needed = true; - (Box::new(sync::now(self.device.clone())) as Box<_>) - } - Err(e) => { - println!("{:?}", e); - (Box::new(sync::now(self.device.clone())) as Box<_>) + { + + let g = hprof::enter("Joining on the framebuffer"); + let mut future = sync::now(self.device.clone()) + .join(acquire_future); + drop(g); + + let g = hprof::enter("Running the kernel and waiting on the future"); + + let future = 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) => { + future.wait(None).unwrap(); + } + Err(FlushError::OutOfDate) => { + self.swapchain_recreate_needed = true; + } + Err(e) => { + println!("{:?}", e); + } } } } @@ -265,4 +302,3 @@ impl<'a> VkProcessor<'a> { -