From 3db8eaf00639906772acd55b2db86b4881eb1da7 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Sun, 22 Sep 2019 01:37:58 -0700 Subject: [PATCH] refactoring the shader container. To Trait or not to Trait? Probably Trait --- src/canvas/canvas_buffer.rs | 19 +-- src/canvas/canvas_shader.rs | 257 ++++++++++++++++++------------------ src/canvas/canvas_state.rs | 57 +++----- src/canvas/canvas_text.rs | 2 +- src/canvas/mod.rs | 3 +- src/vkprocessor.rs | 4 +- 6 files changed, 160 insertions(+), 182 deletions(-) diff --git a/src/canvas/canvas_buffer.rs b/src/canvas/canvas_buffer.rs index 434010b9..eaa62054 100644 --- a/src/canvas/canvas_buffer.rs +++ b/src/canvas/canvas_buffer.rs @@ -2,12 +2,13 @@ use crate::canvas::canvas_state::{CanvasTextureHandle, CanvasImageHandle}; use vulkano::image::{ImmutableImage, AttachmentImage}; use std::sync::Arc; use vulkano::format::{Format, R8Unorm}; -use crate::canvas::canvas_shader::CanvasShader; +use crate::canvas::canvas_shader::GenericShader; use vulkano::sampler::Sampler; use vulkano::descriptor::DescriptorSet; use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; use vulkano::buffer::CpuAccessibleBuffer; use crate::canvas::canvas_text::{CanvasTextCacheHandle, CanvasTextHandle}; +use vulkano::pipeline::GraphicsPipelineAbstract; #[derive(Clone)] pub struct CanvasTexture { @@ -19,11 +20,11 @@ pub struct CanvasTexture { impl CanvasTexture { pub fn get_descriptor_set(&self, - shader: Arc, + pipeline: Arc, sampler: Arc) -> Box { let o: Box = Box::new( PersistentDescriptorSet::start( - shader.clone().get_pipeline().clone(), 0, + pipeline.clone(), 0, ) .add_sampled_image(self.buffer.clone(), sampler.clone()).unwrap() .build().unwrap()); @@ -39,11 +40,11 @@ pub struct CanvasImage { } impl CanvasImage { - pub fn get_descriptor_set(&self, shader: Arc) + pub fn get_descriptor_set(&self, pipeline: Arc) -> Box { let o: Box = Box::new( PersistentDescriptorSet::start( - shader.clone().get_pipeline().clone(), 0, + pipeline.clone(), 0, ) .add_image(self.buffer.clone()).unwrap() .build().unwrap()); @@ -60,11 +61,11 @@ pub struct CanvasTextCache { impl CanvasTextCache { pub fn get_descriptor_set(&self, - shader: Arc, + pipeline: Arc, sampler: Arc) -> Box { let o: Box = Box::new( PersistentDescriptorSet::start( - shader.clone().get_pipeline().clone(), 0, + pipeline.clone(), 0, ) .add_buffer(self.buffer.clone()).unwrap() .build().unwrap()); @@ -82,11 +83,11 @@ pub struct CanvasText { impl CanvasText { pub fn get_descriptor_set(&self, - shader: Arc, + pipeline: Arc, sampler: Arc) -> Box { let o: Box = Box::new( PersistentDescriptorSet::start( - shader.clone().get_pipeline().clone(), 0, + pipeline.clone(), 0, ) .add_sampled_image(self.buffer.clone(), sampler.clone()).unwrap() .build().unwrap()); diff --git a/src/canvas/canvas_shader.rs b/src/canvas/canvas_shader.rs index d4946aef..f23a580c 100644 --- a/src/canvas/canvas_shader.rs +++ b/src/canvas/canvas_shader.rs @@ -13,6 +13,47 @@ use crate::util::vertex_3d::Vertex3D; use vulkano::pipeline::depth_stencil::{DepthStencil, Stencil, StencilOp, Compare, DepthBounds}; use std::collections::HashSet; +/// Inheriting this gives private functions to grab resources +trait CompiledGraphicsPipelineResources { + fn get_paths(filename: String, types: HashSet) -> Vec<(ShaderType, PathBuf)> { + let project_root = + std::env::current_dir() + .expect("failed to get root directory"); + + let mut shader_path = project_root.clone(); + shader_path.push(PathBuf::from("resources/shaders/")); + + let mut paths = Vec::new(); + + for shader_type in types { + match shader_type { + ShaderType::VERTEX => { + let mut shader_path = shader_path.clone(); + shader_path.push(PathBuf::from(filename.clone() + ".vert")); + paths.push((shader_type, shader_path)); + } + ShaderType::FRAGMENT => { + let mut shader_path = shader_path.clone(); + shader_path.push(PathBuf::from(filename.clone() + ".frag")); + paths.push((shader_type, shader_path)); + } + ShaderType::GEOMETRY => { + let mut shader_path = shader_path.clone(); + shader_path.push(PathBuf::from(filename.clone() + ".geom")); + paths.push((shader_type, shader_path)); + } + ShaderType::TESSELLATION => { + let mut shader_path = shader_path.clone(); + shader_path.push(PathBuf::from(filename.clone() + ".tess")); + paths.push((shader_type, shader_path)); + } + } + } + + paths + } +} + /// Typed wrapper for a u32 handle #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CompiledGraphicsPipelineHandle { @@ -20,32 +61,11 @@ pub struct CompiledGraphicsPipelineHandle { } pub trait CompiledGraphicsPipeline { -// fn get_paths(&self, filename: String) -> Vec<(ShaderType, PathBuf)> { -// -// let project_root = -// std::env::current_dir() -// .expect("failed to get root directory"); -// -// let mut shader_path = project_root.clone(); -// shader_path.push(PathBuf::from("resources/shaders/")); -// -// -// -// let mut vertex_shader_path = shader_path.clone(); -// vertex_shader_path.push(PathBuf::from("resources/shaders/")); -// 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")); -// -// (vertex_shader_path, fragment_shader_path) -// } - fn new(filename: String, shaders: HashSet) -> Self; - fn get_name() -> String; - fn get_handle() -> Arc; - fn get_pipeline() -> Arc; - fn recompile(); + fn get_name(&self) -> String; + fn get_handle(&self) -> Arc; + fn get_pipeline(&self) -> Arc; + fn recompile(self, render_pass: Arc) + -> Self where Self: Sized; } /// Legacy ShaderType enum for single type shaders. @@ -54,7 +74,8 @@ pub enum ShaderType { VERTEX = 0, FRAGMENT = 1, GEOMETRY = 2, - TESSELATION = 3, + TESSELLATION_CONTROL = 3, + TESSELLATION_EVALUATION = 4, } @@ -66,121 +87,96 @@ pub struct CanvasShaderHandle { /// CanvasShader holds the pipeline and render pass for the input shader source #[derive(Clone)] -pub struct CanvasShader { - +pub struct GenericShader { graphics_pipeline: Option>, + handle: Arc, + name: String, + shader_types: HashSet, + device: Arc, - pub(crate) handle: Arc, - pub(crate) name: String, } -impl CompiledGraphicsPipeline for CanvasShader { - -// fn get_path(filename: String) -> (PathBuf, PathBuf) { -// let project_root = -// std::env::current_dir() -// .expect("failed to get root directory"); -// -// let mut shader_path = project_root.clone(); -// shader_path.push(PathBuf::from("resources/shaders/")); -// -// 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")); -// -// 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")); -// -// (vertex_shader_path, fragment_shader_path) -// } - - fn new(filename: String, shaders: HashSet) -> Self { - unimplemented!() - } +/// Gives CanvasShader the resource functions +impl CompiledGraphicsPipelineResources for GenericShader {} - fn get_name() -> String { - unimplemented!() +/// Convenience interface so we don't have to juggle shader types +impl CompiledGraphicsPipeline for GenericShader { + fn get_name(&self) -> String { + self.name.clone() } - fn get_handle() -> Arc { - unimplemented!() + fn get_handle(&self) -> Arc { + self.handle.clone() } - fn get_pipeline() -> Arc { - unimplemented!() + fn get_pipeline(&self) -> Arc { + self.graphics_pipeline.clone().unwrap() } - fn recompile() { - unimplemented!() + fn recompile(self, render_pass: Arc) -> GenericShader { + GenericShader::new(self.name, + self.shader_types, + self.device, + self.handle, + render_pass.clone()) } } -impl CanvasShader { +impl GenericShader { - fn get_path(filename: String) -> (PathBuf, PathBuf) { - let project_root = - std::env::current_dir() - .expect("failed to get root directory"); + /// This will explode when the shader does not want to compile + pub fn new(filename: String, + shader_types: HashSet, + device: Arc, + handle: Arc, + render_pass: Arc) -> GenericShader { - let mut shader_path = project_root.clone(); - shader_path.push(PathBuf::from("resources/shaders/")); + let filenames = GenericShader::get_paths(filename.clone(), shader_types.clone()); - 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")); + // TODO: better compile message, run til successful compile - 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")); - (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 shader. - /// This will explode when the shader does not want to compile - pub fn new(filename: String, - capabilities: Capabilities, - queue: Arc, - physical: PhysicalDevice, - device: Arc, - handle: Arc, - render_pass: Arc,) -> CanvasShader { + for shader in filenames { + match shader.0 { + ShaderType::VERTEX => { + let shader = sr::load(filenames.0, filenames.1) + .expect("Shader didn't compile"); - let format = capabilities.supported_formats[0].0; + let vulkano_entry = + sr::parse(&shader) + .expect("failed to parse"); + } + ShaderType::FRAGMENT => { - let filenames = CanvasShader::get_path(filename.clone()); + } + ShaderType::GEOMETRY => { - // TODO: better compile message, run til successful compile - let shader = sr::load(filenames.0, filenames.1) - .expect("Shader didn't compile"); + } + ShaderType::TESSELLATION => { - let vulkano_entry = - sr::parse(&shader) - .expect("failed to parse"); + } + } + } let fragment_shader_module: Arc = unsafe { - let filenames1 = CanvasShader::get_path(filename.clone()); + let filenames1 = GenericShader::get_path(filename.clone()); let shader1 = sr::load(filenames1.0, filenames1.1) .expect("Shader didn't compile"); - vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader1.fragment.clone()) + ShaderModule::from_words(device.clone(), &shader1.fragment.clone()) }.unwrap(); + let vertex_shader_module: Arc = unsafe { - let filenames1 = CanvasShader::get_path(filename.clone()); + + let filenames1 = GenericShader::get_path(filename.clone()); let shader1 = sr::load(filenames1.0, filenames1.1) .expect("Shader didn't compile"); - vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader1.vertex.clone()) + ShaderModule::from_words(device.clone(), &shader1.vertex.clone()) }.unwrap(); - let filenames = CanvasShader::get_path(filename.clone()); - let frag_entry_point = unsafe { Some(fragment_shader_module.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), @@ -199,31 +195,31 @@ impl CanvasShader { }; let stencil = DepthStencil { - depth_compare: Compare::Less, - depth_write: true, - depth_bounds_test: DepthBounds::Disabled, - stencil_front: Stencil { - compare: Compare::Equal, - pass_op: StencilOp::IncrementAndWrap, - fail_op: StencilOp::DecrementAndClamp, - depth_fail_op: StencilOp::Keep, - compare_mask: None, - write_mask: None, - reference: None, - }, - stencil_back: Stencil { - compare: Compare::Equal, - pass_op: StencilOp::Invert, - fail_op: StencilOp::Zero, - depth_fail_op: StencilOp::Zero, - compare_mask: None, - write_mask: None, - reference: None, - }, - }; - - - CanvasShader { + depth_compare: Compare::Less, + depth_write: true, + depth_bounds_test: DepthBounds::Disabled, + stencil_front: Stencil { + compare: Compare::Equal, + pass_op: StencilOp::IncrementAndWrap, + fail_op: StencilOp::DecrementAndClamp, + depth_fail_op: StencilOp::Keep, + compare_mask: None, + write_mask: None, + reference: None, + }, + stencil_back: Stencil { + compare: Compare::Equal, + pass_op: StencilOp::Invert, + fail_op: StencilOp::Zero, + depth_fail_op: StencilOp::Zero, + compare_mask: None, + write_mask: None, + reference: None, + }, + }; + + + GenericShader { graphics_pipeline: Some(Arc::new(GraphicsPipeline::start() .vertex_input(SingleBufferDefinition::::new()) @@ -256,6 +252,7 @@ impl CanvasShader { device: device, handle: handle.clone(), name: filename.clone(), + shader_types: shader_types.clone(), } } } diff --git a/src/canvas/canvas_state.rs b/src/canvas/canvas_state.rs index 5083c942..34d27c13 100644 --- a/src/canvas/canvas_state.rs +++ b/src/canvas/canvas_state.rs @@ -21,7 +21,7 @@ use vulkano::descriptor::descriptor::DescriptorDescTy::TexelBuffer; use crate::canvas::canvas_frame::CanvasFrame; use std::hash::Hash; use crate::canvas::canvas_text::{CanvasText, CanvasTextHandle}; -use crate::canvas::canvas_shader::{CanvasShader, CanvasShaderHandle}; +use crate::canvas::canvas_shader::{GenericShader, CanvasShaderHandle, CompiledGraphicsPipelineHandle, CompiledGraphicsPipeline}; use crate::canvas::canvas_buffer::{CanvasImage, CanvasTexture, CanvasTextCache}; use crate::util::vertex_3d::Vertex3D; use vulkano::pipeline::depth_stencil::{StencilFaceFlags, DynamicStencilValue}; @@ -32,7 +32,6 @@ use vulkano::pipeline::depth_stencil::{StencilFaceFlags, DynamicStencilValue}; /// Split out to two drawables? /// 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)>; @@ -84,7 +83,7 @@ pub struct CanvasState { // hold the image, texture, and shader buffers the same was as we do CompuState image_buffers: Vec>, texture_buffers: Vec>, - shader_buffers: Vec>, + shader_buffers: Vec>>, text_buffers: Vec>, // Hold onto the vertices we get from the Compu and Canvas Frames @@ -218,7 +217,6 @@ impl CanvasState { /// Using the dimensions and suggested usage, load a CanvasImage and return it's handle pub fn create_text_buffers(&mut self, dimensions: (u32, u32)) -> Arc { - let handle = Arc::new(CanvasTextHandle { handle: self.text_buffers.len() as u32 }); // // let text = CanvasText { @@ -348,39 +346,21 @@ impl CanvasState { filename: String, shader_type: ShaderType, physical: PhysicalDevice, - capabilities: Capabilities) -> Option> { + capabilities: Capabilities) -> Option> { - let handle = Arc::new(CanvasShaderHandle { + let handle = Arc::new(CompiledGraphicsPipelineHandle { handle: self.shader_buffers.len() as u32 }); - // TODO : what is even going on here - let shader = match shader_type { - ShaderType::SOLID => { - Arc::new(CanvasShader::new( - filename.clone(), - capabilities.clone(), - self.queue.clone(), - physical.clone(), - self.device.clone(), - handle.clone(), - self.render_pass.clone()) - ) - } - ShaderType::IMAGE | ShaderType::TEXTURED => { - Arc::new(CanvasShader::new( - filename.clone(), - capabilities.clone(), - self.queue.clone(), - physical.clone(), - self.device.clone(), - handle.clone(), - self.render_pass.clone()) - ) - } - }; - self.shader_buffers.push(shader.clone()); + let shader : Box = Box::new(GenericShader::new( + filename.clone(), + self.device.clone(), + handle.clone(), + self.render_pass.clone() + )); + + self.shader_buffers.push(Arc::new(shader)); Some(handle) } @@ -398,10 +378,10 @@ impl CanvasState { /// Using the shader name, iterates through the stored textures and matches by the name pub fn get_shader_handle(&self, shader_name: String) - -> Option> { + -> Option> { for shader in self.shader_buffers.clone() { - if shader.name == shader_name { - return Some(shader.handle.clone()); + if shader.get_name() == shader_name { + return Some(shader.get_handle().clone()); } } None @@ -487,7 +467,7 @@ impl CanvasState { } /// 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 { + fn get_solid_color_descriptor_set(&self, kernel: Arc) -> Box { let o: Box = Box::new( PersistentDescriptorSet::start( kernel.clone().get_pipeline().clone(), 0, @@ -547,7 +527,7 @@ impl CanvasState { for (image_handle, vertex_buffer) in self.image_vertex_buffer.clone() { let handle = image_handle.clone().handle as usize; let descriptor_set = self.image_buffers.get(handle).clone().unwrap().clone() - .get_descriptor_set(shader.clone()); + .get_descriptor_set(shader.get_pipeline().clone()); command_buffer = command_buffer.draw( shader.get_pipeline().clone(), @@ -555,7 +535,6 @@ impl CanvasState { &self.dynamic_state.clone(), vec![vertex_buffer], vec![descriptor_set], (), ).unwrap(); - } } @@ -569,7 +548,7 @@ impl CanvasState { for (texture_handle, vertex_buffer) in self.textured_vertex_buffer.clone() { let handle = texture_handle.clone().handle as usize; let descriptor_set = self.texture_buffers.get(handle).clone().unwrap().clone() - .get_descriptor_set(shader.clone(), self.sampler.clone()); + .get_descriptor_set(shader.get_pipeline(), self.sampler.clone()); command_buffer = command_buffer.draw( shader.get_pipeline().clone(), diff --git a/src/canvas/canvas_text.rs b/src/canvas/canvas_text.rs index 89e6f982..c030e67e 100644 --- a/src/canvas/canvas_text.rs +++ b/src/canvas/canvas_text.rs @@ -41,7 +41,7 @@ impl CanvasText { let cache = Cache::builder().dimensions(CACHE_WIDTH as u32, CACHE_HEIGHT as u32).build(); let cache_pixel_buffer = vec!(0; CACHE_WIDTH * CACHE_HEIGHT); - + let font_data = include_bytes!("../../resources/fonts/sansation.ttf"); let font = Font::from_bytes(font_data as &[u8]).unwrap(); diff --git a/src/canvas/mod.rs b/src/canvas/mod.rs index 71465234..59e5ae2d 100644 --- a/src/canvas/mod.rs +++ b/src/canvas/mod.rs @@ -6,4 +6,5 @@ pub mod canvas_text; pub mod canvas_buffer; -use crate::canvas::canvas_frame::CanvasFrame; \ No newline at end of file +use crate::canvas::canvas_frame::CanvasFrame; +use crate::canvas::canvas_shader::GenericShader; \ No newline at end of file diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index 6a16845b..33623eba 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -16,7 +16,7 @@ use crate::canvas::canvas_frame::CanvasFrame; use crate::compute::compu_kernel::{CompuKernel, CompuKernelHandle}; use crate::compute::compu_buffer::{CompuBuffers, CompuBufferHandle}; use std::time::Duration; -use crate::canvas::canvas_shader::CanvasShaderHandle; +use crate::canvas::canvas_shader::{CanvasShaderHandle, CompiledGraphicsPipeline, CompiledGraphicsPipelineHandle}; use vulkano::pipeline::depth_stencil::{DynamicStencilValue, StencilFaceFlags}; /// VKProcessor holds the vulkan instance information, the swapchain, and the compute and canvas states @@ -171,7 +171,7 @@ impl<'a> VkProcessor<'a> { } /// O(n) Lookup for the matching shader string - pub fn get_shader_handle(&self, shader_name: String) -> Option> { + pub fn get_shader_handle(&self, shader_name: String) -> Option> { self.canvas.get_shader_handle(shader_name) }