From 26b73c48a87a31fd4de9b3e5b8418969e2930c94 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Mon, 9 Sep 2019 20:57:15 -0700 Subject: [PATCH] working on docs --- src/canvas.rs | 149 +++++++++++++++++++------------------------ src/canvas_shader.rs | 20 ++++-- src/compu_state.rs | 5 +- src/main.rs | 48 +++++++------- src/vkprocessor.rs | 25 +++++++- 5 files changed, 130 insertions(+), 117 deletions(-) diff --git a/src/canvas.rs b/src/canvas.rs index 5c73e774..57eb8f0b 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -23,46 +23,25 @@ use crate::canvas_frame::CanvasFrame; use std::hash::Hash; use crate::canvas_shader::CanvasShader; use crate::canvas_buffer::{CanvasImage, CanvasTexture}; - -// Canvas is the accumulator of Sprites for drawing - -// Needs to know: -// textured? -// colored? -// vertices - /* - 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) @@ -73,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); @@ -80,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, @@ -88,22 +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 CanvasState { dynamic_state: DynamicState, @@ -158,8 +135,6 @@ impl CanvasState { device: Arc, 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 }, @@ -168,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![], @@ -279,6 +241,22 @@ impl CanvasState { Some(handle) } + /// 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() { @@ -289,6 +267,7 @@ impl CanvasState { None } + /// Using the texture handle, grab the stored texture and return the buffer pub fn get_texture(&self, texture_handle: Arc) -> Arc> { let handle = texture_handle.handle as usize; @@ -300,35 +279,18 @@ 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.image_vertex_buffer.clear(); - - - /* - So a bit of brainstorming with the shaders: - - I compile shaders into their respective buffers and add them to a descriptor set - along with the textures or whatever other resource buffer - - So I'm gonna fix that texturing issue by adding vertex texture coordinate attributes - - Still don't really know how I'm gonna do this... - - * Going to definitely need to use the CpuAccessbileBuffer - * Maybe calculate deltas between frames??? - * - - - */ + /// draw(canvas_fame) stored all the intermediate information, this function + /// allocates the vertex buffers using that information + fn allocate_vertex_buffers(&mut self) { self.colored_vertex_buffer.clear(); { @@ -356,8 +318,24 @@ impl CanvasState { ); } } + + 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( @@ -366,6 +344,7 @@ impl CanvasState { o } + /// Pushes the draw commands s pub fn draw_commands(&self, mut command_buffer: AutoCommandBufferBuilder, framebuffers: Vec>, @@ -392,10 +371,9 @@ impl CanvasState { ).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(); @@ -411,21 +389,26 @@ impl CanvasState { vec![descriptor_set], (), ).unwrap(); } - /*for (shader_type, kernel) in self.shader_kernels.clone().iter() { - match shader_type { - ShaderType::SOLID => { - } - 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 mut shader = self.shader_buffers.get("simple-image").unwrap().clone(); + + if !self.image_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 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_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 c060d481..fae5798c 100644 --- a/src/compu_state.rs +++ b/src/compu_state.rs @@ -75,7 +75,6 @@ impl CompuState { handle } - // TODO : THIS IS BROKEN pub fn get_kernel_handle(&self, kernel_name: String) -> Option> { for i in self.kernels.clone() { if i.get_name() == kernel_name { @@ -127,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 b975520d..b9140204 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,24 +28,24 @@ 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; - -mod canvas; -mod canvas_frame; -mod canvas_shader; -mod canvas_buffer; - -mod compu_state; -mod compu_frame; -mod compu_sprite; -mod compu_kernel; -mod compu_buffer; +pub mod util; +pub mod timer; +pub mod input; +pub mod vkprocessor; +pub mod vertex_2d; +pub mod vertex_3d; +pub mod sprite; + +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; /* @@ -56,7 +56,9 @@ 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(); @@ -166,12 +168,12 @@ fn main() { let mut compu_frame = CompuFrame::new(); compu_frame.add(compute_buffer.clone(), compute_kernel.clone()); - // compu_frame.add_with_image_swap(compute_buffer.clone(), compute_kernel.clone(), &compu_sprite1); + compu_frame.add_with_image_swap(compute_buffer.clone(), compute_kernel.clone(), &compu_sprite1); let mut canvas = CanvasFrame::new(); -// canvas.draw(&sprite); -// canvas.draw(&sprite2); -// canvas.draw(&sprite3); + canvas.draw(&sprite); + canvas.draw(&sprite2); + canvas.draw(&sprite3); //canvas.draw(&compu_sprite1); { let g = hprof::enter("Run"); diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index b29eeaec..2aad7ed7 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -11,12 +11,15 @@ 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, @@ -39,7 +42,11 @@ 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(); @@ -109,7 +117,8 @@ impl<'a> VkProcessor<'a> { 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(); @@ -130,17 +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) }