use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use std::collections::{HashMap, HashSet}; use vulkano::buffer::{BufferAccess, BufferUsage, ImmutableBuffer, CpuAccessibleBuffer}; use std::sync::Arc; use vulkano::format::{ClearValue, Format, R8Unorm}; use vulkano::framebuffer::{FramebufferAbstract, Framebuffer, RenderPass, RenderPassAbstract}; use vulkano::device::{Device, Queue}; use vulkano::instance::PhysicalDevice; use vulkano::image::immutable::ImmutableImage; use vulkano::image::{Dimensions, ImageAccess, ImageDimensions, SwapchainImage, ImageUsage, AttachmentImage, ImageLayout}; use vulkano::sampler::{Sampler, SamplerAddressMode, MipmapMode, Filter}; use vulkano::descriptor::DescriptorSet; use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; use std::path::PathBuf; use image::GenericImageView; use std::iter::FromIterator; use vulkano::swapchain::Capabilities; use winit::Window; use vulkano::pipeline::viewport::Viewport; use vulkano::descriptor::descriptor::DescriptorDescTy::TexelBuffer; use crate::canvas::canvas_frame::CanvasFrame; use std::hash::Hash; use crate::util::vertex_3d::{Vertex3D, TextVertex3D}; use vulkano::pipeline::depth_stencil::{StencilFaceFlags, DynamicStencilValue}; use vulkano::memory::pool::PotentialDedicatedAllocation::Generic; use std::borrow::Borrow; use std::fs::File; use std::io::Read; use rusttype::{Font, PositionedGlyph, Scale, Rect, point, GlyphId, Line, Curve, Segment}; use vulkano::pipeline::vertex::VertexDefinition; use crate::canvas::managed::shader::dynamic_vertex::RuntimeVertexDef; use crate::canvas::managed::handles::{CanvasTextureHandle, CanvasImageHandle, CanvasFontHandle, CompiledGraphicsPipelineHandle, Handle}; use crate::canvas::managed::gpu_buffers::{CanvasImage, CanvasTexture, CanvasFont}; use crate::canvas::managed::shader::shader_common::CompiledGraphicsPipeline; use crate::canvas::managed::shader::generic_shader::GenericShader; // I don't think this is going to work without getting into Box'ing pub trait DrawableTest { fn get_vertices(&self) -> Vec; fn get_instances(&self) -> Vec; fn get_handle(&self) -> H; } /// A drawable object can be passed into a CanvasFrame to be rendered /// Very generic implementation. (N % 2 == 0) vertices, ditto for texture coords, and rgba color /// Provides Image and Texture handles for drawing pub trait Drawable { fn get_vertices(&self) -> Vec<(f32, f32, f32)>; fn get_color(&self) -> (f32, f32, f32, f32); fn get_ti_coords(&self) -> Vec<(f32, f32)>; fn get_texture_handle(&self) -> Option>; fn get_image_handle(&self) -> Option>; // fn get_text_handle(&self) -> Option>; fn collect(&self) -> Vec { let color = self.get_color(); // self.get_vertices().iter().zip(self.get_ti_coords().iter()).map(|(a, b)| // Vertex3D { // v_position: [a.0, a.1, a.2], // color: [color.0, color.1, color.2, color.3], // ti_position: [b.0, b.1], // }).collect() // TODO vec![RuntimeVertexDef::from_primitive(0)] } } /// Canvas state is used for storage of texture and image buffers in addition to vertex buffers /// Canvas state also contains logic for writing the stored buffers to the command_buffer #[derive(Clone)] pub struct CanvasState { /// Generated during new() dynamic_state: DynamicState, /// Generated during new() sampler: Arc, // hold the image, texture, and Fonts the same was as we do CompuState image_buffers: Vec>, texture_buffers: Vec>, font_buffers: Vec>, // Compiled Graphics pipelines have a handle which self describe their position in this vector shader_buffers: Vec>>, // Hold onto the vertices we get from the Compu and Canvas Frames // When the run comes around, push the vertices to the GPU colored_vertex_buffer: Vec>, textured_vertex_buffer: HashMap, Arc<(dyn BufferAccess + Send + Sync)>>, image_vertex_buffer: HashMap, Arc<(dyn BufferAccess + Send + Sync)>>, text_instances: HashMap, Arc<(dyn BufferAccess + Send + Sync)>>, // Looks like we gotta hold onto the queue for managing textures queue: Arc, device: Arc, render_pass: Arc, } impl CanvasState { /// This method is called once during initialization, then again whenever the window is resized pub fn window_size_dependent_setup(&mut self, images: &[Arc>]) -> Vec> { let dimensions = images[0].dimensions(); self.dynamic_state.viewports = Some(vec![Viewport { origin: [0.0, 0.0], dimensions: [dimensions.width() as f32, dimensions.height() as f32], depth_range: 0.0..1.0, }]); let dimensions = [dimensions.width(), dimensions.height()]; let depth_buffer = AttachmentImage::transient(self.device.clone(), dimensions, Format::D32Sfloat_S8Uint).unwrap(); images.iter().map(|image| { Arc::new( Framebuffer::start(self.render_pass.clone()) .add(image.clone()).unwrap() .add(depth_buffer.clone()).unwrap() .build().unwrap() ) as Arc }).collect::>() } /// Creates a Canvas State. Which at this point is pretty empty pub fn new(queue: Arc, device: Arc, physical: PhysicalDevice, capabilities: Capabilities) -> CanvasState { let format = capabilities.supported_formats[0].0; let render_pass = Arc::new(vulkano::single_pass_renderpass!( device.clone(), // Attachments are outgoing like f_color attachments: { // `color` is a custom name we give to the first and only attachment. color: { // `load: Clear` means that we ask the GPU to clear the content of this // attachment at the start of the drawing. load: Clear, // `store: Store` means that we ask the GPU to store the output of the draw // in the actual image. We could also ask it to discard the result. store: Store, // `format: ` indicates the type of the format of the image. This has to // be one of the types of the `vulkano::format` module (or alternatively one // of your structs that implements the `FormatDesc` trait). Here we use the // same format as the swapchain. format: format, samples: 1, }, depth: { load: Clear, store: DontCare, format: Format::D32Sfloat_S8Uint, samples: 1, } }, pass: { // We use the attachment named `color` as the one and only color attachment. color: [color], // No depth-stencil attachment is indicated with empty brackets. depth_stencil: {depth} } ).unwrap()); CanvasState { // TODO: Might need to move this dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: Some(DynamicStencilValue { face: StencilFaceFlags::StencilFrontAndBack, value: 0xFF, }), write_mask: Some(DynamicStencilValue { face: StencilFaceFlags::StencilFrontAndBack, value: 0xFF, }), reference: Some(DynamicStencilValue { face: StencilFaceFlags::StencilFrontAndBack, value: 0xFF, }), }, sampler: Sampler::new(device.clone(), Filter::Linear, Filter::Linear, MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(), image_buffers: vec![], texture_buffers: vec![], shader_buffers: vec![], font_buffers: vec![], colored_vertex_buffer: vec![], textured_vertex_buffer: Default::default(), image_vertex_buffer: Default::default(), text_instances: HashMap::default(), queue: queue.clone(), device: device.clone(), render_pass: render_pass.clone(), } } /// Using the dimensions and suggested usage, load a CanvasImage and return it's handle 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 image = CanvasImage { handle: handle.clone(), buffer: AttachmentImage::with_usage( self.device.clone(), [dimensions.0, dimensions.1], Format::R8G8B8A8Uint, usage).unwrap(), size: dimensions, }; self.image_buffers.push(Arc::new(image)); handle } /// Return the image buffer from an input image handle pub fn get_image(&self, image_handle: Arc) -> Arc { self.image_buffers.get((*image_handle).clone().get_handle() as usize).unwrap() .clone().buffer.clone() } /// Load a texture buffer from an input filename fn get_texture_from_file(&self, image_filename: String) -> Arc> { let project_root = std::env::current_dir() .expect("failed to get root directory"); let mut compute_path = project_root.clone(); compute_path.push(PathBuf::from("resources/images/")); compute_path.push(PathBuf::from(image_filename)); let img = image::open(compute_path).expect("Couldn't find image"); let xy = img.dimensions(); let data_length = xy.0 * xy.1 * 4; let pixel_count = img.raw_pixels().len(); let mut image_buffer = Vec::new(); if pixel_count != data_length as usize { println!("Creating apha channel..."); for i in img.raw_pixels().iter() { if (image_buffer.len() + 1) % 4 == 0 { image_buffer.push(255); } image_buffer.push(*i); } image_buffer.push(255); } else { image_buffer = img.raw_pixels(); } let (texture, tex_future) = ImmutableImage::from_iter( image_buffer.iter().cloned(), Dimensions::Dim2d { width: xy.0, height: xy.1 }, Format::R8G8B8A8Srgb, self.queue.clone(), ).unwrap(); texture } /// Load a texture using it's filename from a file. Returns the handle of the loaded texture pub fn load_texture(&mut self, filename: String) -> Option> { let texture_buffer = self.get_texture_from_file(filename.clone()); let handle = Arc::new(CanvasTextureHandle { handle: self.texture_buffers.len() as u32 }); let texture = Arc::new(CanvasTexture { handle: handle.clone(), buffer: self.get_texture_from_file(filename.clone()), name: filename.clone(), size: (0, 0), }); self.texture_buffers.push(texture); 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) -> Option> where T: CompiledGraphicsPipeline { let handle = Arc::new(CompiledGraphicsPipelineHandle { handle: self.shader_buffers.len() as u32 }); let shader: Box = Box::new(T::new( filename.clone(), self.device.clone(), handle.clone(), self.render_pass.clone(), )); self.shader_buffers.push(Arc::new(shader)); Some(handle) } /// Using the dimensions and suggested usage, load a CanvasImage and return it's handle pub fn load_font(&mut self, name: String) -> Arc { let handle = Arc::new(CanvasFontHandle { handle: self.font_buffers.len() as u32 }); self.font_buffers.push(Arc::new({ let font = Font::from_bytes({ let mut f = File::open("resources/fonts/sansation.ttf").expect("Font file not found"); let mut font_data = Vec::new(); f.read_to_end(&mut font_data).expect("Dont know"); font_data }).unwrap(); let mut current_x = 0; let mut current_y = 0; let mut accumulator = Vec::new(); for i in (0..255) { let glyph = font.glyph('d'); let s = glyph.scaled(Scale{ x: 1.0, y: 1.0 }); let shape = s.shape().unwrap(); for contour in shape { for segment in contour.segments { match segment { Segment::Line(l) => { accumulator.push(TextVertex3D { position: [l.p[0].x as f32, l.p[0].y as f32, 0.0], }); }, Segment::Curve(c) => { accumulator.push(TextVertex3D { position: [c.p[0].x as f32, c.p[0].y as f32, 0.0], }); } } } } } CanvasFont { handle: handle.clone(), font: font.clone(), name: name, buffer: ImmutableBuffer::from_iter( accumulator.iter().cloned(), BufferUsage::vertex_buffer(), self.queue.clone()).unwrap().0, } })); handle } /// 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()); } } None } /// Using the shader name, iterates through the stored shaders and matches by the name pub fn get_shader_handle(&self, shader_name: String) -> Option> { for shader in self.shader_buffers.clone() { if shader.get_name() == shader_name { return Some(shader.get_handle().clone()); } } None } /// Using the font name, iterates through the stored fonts and matches by the name pub fn get_font_handle(&self, font_name: String) -> Option> { for font in self.font_buffers.clone() { if font.name == font_name { return Some(font.handle.clone()); } } 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.get_handle() as usize; if let Some(i) = self.texture_buffers.get(handle) { return i.clone().buffer.clone(); } else { panic!("{} : Texture not loaded", handle); } } /// Scrape all the values from the CanvasFrame and then allocate the vertex buffers pub fn draw(&mut self, canvas_frame: CanvasFrame) { // Consume the canvas frame let mut textured_drawables = canvas_frame.textured_drawables; let mut colored_drawables = canvas_frame.colored_drawables; let mut image_drawables = canvas_frame.image_drawables; let mut text_drawables = canvas_frame.text_drawables; // Walk through the consumed items and allocate them to GPU buffers self.colored_vertex_buffer.clear(); { let g = hprof::enter("Colored Vertex Buffer"); self.colored_vertex_buffer.push( ImmutableBuffer::from_iter( colored_drawables.iter().cloned(), BufferUsage::vertex_buffer(), self.queue.clone(), ).unwrap().0 ); } self.textured_vertex_buffer.clear(); { let g = hprof::enter("Textured Vertex Buffer"); for (k, v) in textured_drawables.drain() { let vertex_buffer = v.clone().get(0).unwrap().clone(); // TODO // v.clone().iter() // .fold(Vec::new(), |mut a: Vec, b| { // a.extend(b); // a // }); self.textured_vertex_buffer.insert( k.clone(), ImmutableBuffer::from_iter( vertex_buffer.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 image_drawables.drain() { let vertex_buffer = v.clone().get(0).unwrap().clone(); // TODO // v.clone().iter() // .fold(Vec::new(), |mut a: Vec<&RuntimeVertexDef>, b| { // a.extend(b); // a // }); self.image_vertex_buffer.insert( k.clone(), ImmutableBuffer::from_iter( vertex_buffer.iter().cloned(), BufferUsage::vertex_buffer(), self.queue.clone(), ).unwrap().0, ); } } self.text_instances.clear(); { let g = hprof::enter("Text Instance Vertex Buffer"); for (k, v) in text_drawables.drain() { self.text_instances.insert( k.clone(), ImmutableBuffer::from_iter( v.iter().cloned(), BufferUsage::all(), 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, ).build().unwrap()); o } /// Pushes the draw commands to the command buffer. Requires the framebuffers and /// image number to be passed in as they are taken care of by the vkprocessor pub fn draw_commands(&mut self, mut command_buffer: AutoCommandBufferBuilder, framebuffers: Vec>, image_num: usize) -> AutoCommandBufferBuilder { // Specify the color to clear the framebuffer with i.e. blue let clear_values = vec!( ClearValue::Float([0.0, 0.0, 1.0, 1.0]), ClearValue::DepthStencil((1.0, 0x00)), ); self.dynamic_state = DynamicState { line_width: None, viewports: self.dynamic_state.viewports.clone(), scissors: None, compare_mask: None, write_mask: None, reference: None, }; let mut command_buffer = command_buffer.begin_render_pass( framebuffers[image_num].clone(), false, clear_values.clone(), ).unwrap(); // Solid colors let mut shader = self.shader_buffers.get( self.get_shader_handle(String::from("color-passthrough")) .unwrap().clone().get_handle() as usize ).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 let mut shader = self.shader_buffers.get( self.get_shader_handle(String::from("simple_image")) .unwrap().clone().get_handle() as usize ).unwrap(); if !self.image_vertex_buffer.is_empty() { for (image_handle, vertex_buffer) in self.image_vertex_buffer.clone() { let handle = image_handle.clone().get_handle() as usize; let descriptor_set = self.image_buffers.get(handle).clone().unwrap().clone() .get_descriptor_set(shader.get_pipeline().clone()); command_buffer = command_buffer.draw( shader.get_pipeline().clone(), // Multiple vertex buffers must have their definition in the pipeline! &self.dynamic_state.clone(), vec![vertex_buffer], vec![descriptor_set], (), ).unwrap(); } } // Textures let mut shader = self.shader_buffers.get( self.get_shader_handle(String::from("simple_texture")) .unwrap().clone().get_handle() as usize ).unwrap(); if !self.textured_vertex_buffer.is_empty() { for (texture_handle, vertex_buffer) in self.textured_vertex_buffer.clone() { let handle = texture_handle.clone().get_handle() as usize; let descriptor_set = self.texture_buffers.get(handle).clone().unwrap().clone() .get_descriptor_set(shader.get_pipeline(), self.sampler.clone()); command_buffer = command_buffer.draw( shader.get_pipeline().clone(), // Multiple vertex buffers must have their definition in the pipeline! &self.dynamic_state.clone(), vec![vertex_buffer], vec![descriptor_set], (), ).unwrap(); } } // Text let mut shader = self.shader_buffers.get( self.get_shader_handle(String::from("simple_text")) .unwrap().clone().get_handle() as usize ).unwrap(); // // if !self.text_instances.is_empty() { // for (font_handle, instance_buffer) in self.text_instances.clone() { // let handle = font_handle.clone().handle as usize; // let font = self.font_buffers.get(handle).clone().unwrap().clone(); // let descriptor_set = CanvasFont::get_descriptor_set(shader.get_pipeline()); // // command_buffer = command_buffer.draw( // shader.get_pipeline().clone(), // // Multiple vertex buffers must have their definition in the pipeline! // &self.dynamic_state.clone(), // vec![font.get_vertex_buffer().clone(), instance_buffer.clone()], // (), (), // ).unwrap(); // } // } command_buffer .end_render_pass() .unwrap() } }