From 5a888a4163b6a286eab1f8fe3589c4a7613f0588 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Tue, 24 Sep 2019 22:39:24 -0700 Subject: [PATCH] hitting this damn shader module again. Very unergonomic interface with the fact that the entry point doesn't just own the shadermodule --- src/canvas/canvas_shader.rs | 186 ++++++++++++++++++++++++------------ src/canvas/canvas_state.rs | 13 +-- src/compute/compu_buffer.rs | 5 +- src/compute/compu_kernel.rs | 18 ++-- src/vkprocessor.rs | 10 +- 5 files changed, 144 insertions(+), 88 deletions(-) diff --git a/src/canvas/canvas_shader.rs b/src/canvas/canvas_shader.rs index f23a580c..6a13c6be 100644 --- a/src/canvas/canvas_shader.rs +++ b/src/canvas/canvas_shader.rs @@ -1,17 +1,23 @@ use vulkano::device::{Device, Queue}; -use vulkano::instance::{PhysicalDevice, QueueFamily}; +use vulkano::instance::{PhysicalDevice, QueueFamily, LayerProperties}; use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract, GraphicsPipelineBuilder}; use std::sync::Arc; use std::ffi::CStr; use std::path::PathBuf; use shade_runner as sr; use vulkano::framebuffer::{Subpass, RenderPassAbstract, Framebuffer, FramebufferAbstract}; -use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, SpecializationConstants, SpecializationMapEntry}; +use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, SpecializationConstants, SpecializationMapEntry, GeometryShaderExecutionMode, GraphicsEntryPointAbstract, GraphicsEntryPoint, EmptyEntryPointDummy}; use vulkano::swapchain::Capabilities; use vulkano::pipeline::vertex::SingleBufferDefinition; use crate::util::vertex_3d::Vertex3D; use vulkano::pipeline::depth_stencil::{DepthStencil, Stencil, StencilOp, Compare, DepthBounds}; -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; +use shade_runner::{Layout, Output, Input}; +use vulkano::descriptor::pipeline_layout::PipelineLayout; +use std::marker::PhantomData; +use vulkano::pipeline::input_assembly::PrimitiveTopology; +use vulkano::pipeline::blend::{Blend, AttachmentsBlend}; +use vulkano::pipeline::vertex::BufferlessDefinition; /// Inheriting this gives private functions to grab resources trait CompiledGraphicsPipelineResources { @@ -42,9 +48,14 @@ trait CompiledGraphicsPipelineResources { shader_path.push(PathBuf::from(filename.clone() + ".geom")); paths.push((shader_type, shader_path)); } - ShaderType::TESSELLATION => { + ShaderType::TESSELLATION_CONTROL => { let mut shader_path = shader_path.clone(); - shader_path.push(PathBuf::from(filename.clone() + ".tess")); + shader_path.push(PathBuf::from(filename.clone() + ".tesscont")); + paths.push((shader_type, shader_path)); + } + ShaderType::TESSELLATION_EVALUATION => { + let mut shader_path = shader_path.clone(); + shader_path.push(PathBuf::from(filename.clone() + ".tesseval")); paths.push((shader_type, shader_path)); } } @@ -65,7 +76,7 @@ pub trait CompiledGraphicsPipeline { fn get_handle(&self) -> Arc; fn get_pipeline(&self) -> Arc; fn recompile(self, render_pass: Arc) - -> Self where Self: Sized; + -> Self where Self: Sized; } /// Legacy ShaderType enum for single type shaders. @@ -116,83 +127,135 @@ impl CompiledGraphicsPipeline for GenericShader { fn recompile(self, render_pass: Arc) -> GenericShader { GenericShader::new(self.name, - self.shader_types, self.device, self.handle, render_pass.clone()) } } -impl GenericShader { +/* - /// 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 { +Realistically, what should the API for this thing look like... - let filenames = GenericShader::get_paths(filename.clone(), shader_types.clone()); +It's going to just generate a pipeline. But that consists of loading and compiling various shaders, + and generating a pipeline for those shaders and other customer behaviour. - // TODO: better compile message, run til successful compile +This best works I think if I allow users to + A.) impl from a base trait which allows resource lookup + B.) Generate 1 of each of the types of shaders + C.) Modify specilization constants, whatever that might mean + D.) impl from a base trait which defines it's interface +*/ +impl GenericShader { - for shader in filenames { - match shader.0 { - ShaderType::VERTEX => { - let shader = sr::load(filenames.0, filenames.1) - .expect("Shader didn't compile"); + pub fn ret(&self) -> Option> { - let vulkano_entry = - sr::parse(&shader) - .expect("failed to parse"); - } - ShaderType::FRAGMENT => { + let compiled_shader = sr::load_vertex("dfqwefqwef") + .expect("Shader didn't compile"); - } - ShaderType::GEOMETRY => { + let vulkano_entry = + sr::parse(&compiled_shader) + .expect("failed to parse"); - } - ShaderType::TESSELLATION => { + let shader_module: Arc = unsafe { + ShaderModule::from_words(self.device.clone(), &compiled_shader.spriv.clone()) + }.unwrap(); - } - } + let s = ShaderType::VERTEX; + + let shader_type = match s { + ShaderType::VERTEX => { GraphicsShaderType::Vertex } + ShaderType::FRAGMENT => { GraphicsShaderType::Fragment } + ShaderType::GEOMETRY => { GraphicsShaderType::Geometry(GeometryShaderExecutionMode::Triangles) } + ShaderType::TESSELLATION_CONTROL => { GraphicsShaderType::TessellationControl } + ShaderType::TESSELLATION_EVALUATION => { GraphicsShaderType::TessellationEvaluation } + }; + + unsafe { + Some(GraphicsEntryPoint { + module: &shader_module, + name: &CStr::from_bytes_with_nul_unchecked(b"main\0"), + input: vulkano_entry.input.unwrap(), + layout: vulkano_entry.layout, + output: vulkano_entry.output.unwrap(), + ty: shader_type, + marker: PhantomData::default(), + }) } - let fragment_shader_module: Arc = unsafe { - let filenames1 = GenericShader::get_path(filename.clone()); - let shader1 = sr::load(filenames1.0, filenames1.1) - .expect("Shader didn't compile"); - ShaderModule::from_words(device.clone(), &shader1.fragment.clone()) - }.unwrap(); + } + /// This will explode when the shader does not want to compile + pub fn new(filename: String, + device: Arc, + handle: Arc, + render_pass: Arc) -> GenericShader { + let mut shader_types : HashSet = vec![ + ShaderType::VERTEX, + ShaderType::FRAGMENT, + ].iter().cloned().collect(); + + let filenames = GenericShader::get_paths(filename.clone(), shader_types.clone()); - let vertex_shader_module: Arc = unsafe { - let filenames1 = GenericShader::get_path(filename.clone()); - let shader1 = sr::load(filenames1.0, filenames1.1) + // let mut c = Vec::new(); + + let mut vertex_entry_point : Option> + = None; + let mut fragment_entry_point : Option> + = None; + + for shader in filenames { + let compiled_shader = sr::load_vertex(shader.1) .expect("Shader didn't compile"); - ShaderModule::from_words(device.clone(), &shader1.vertex.clone()) - }.unwrap(); + let vulkano_entry = + sr::parse(&compiled_shader) + .expect("failed to parse"); + + let shader_module: Arc = unsafe { + ShaderModule::from_words(device.clone(), &compiled_shader.spriv.clone()) + }.unwrap(); + + let shader_type = match shader.0 { + ShaderType::VERTEX => { GraphicsShaderType::Vertex } + ShaderType::FRAGMENT => { GraphicsShaderType::Fragment } + ShaderType::GEOMETRY => { GraphicsShaderType::Geometry(GeometryShaderExecutionMode::Triangles) } + ShaderType::TESSELLATION_CONTROL => { GraphicsShaderType::TessellationControl } + ShaderType::TESSELLATION_EVALUATION => { GraphicsShaderType::TessellationEvaluation } + }; + + let entry_point: Option> = unsafe { + Some(GraphicsEntryPoint { + module: &shader_module, + name: &CStr::from_bytes_with_nul_unchecked(b"main\0"), + input: vulkano_entry.input.unwrap(), + layout: vulkano_entry.layout, + output: vulkano_entry.output.unwrap(), + ty: shader_type, + marker: PhantomData::default(), + }) + }; - let frag_entry_point = unsafe { - Some(fragment_shader_module.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)) - }; + let shader_type = match shader.0 { + ShaderType::VERTEX => { vertex_entry_point = Some(entry_point.clone().unwrap()) } + ShaderType::FRAGMENT => { fragment_entry_point = Some(entry_point.clone().unwrap()) } + _ => {} + }; - let vertex_entry_point = unsafe { - Some(vertex_shader_module.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)) - }; + // c.push((entry_point.unwrap().clone(), shader_module.clone())); + } let stencil = DepthStencil { depth_compare: Compare::Less, @@ -218,13 +281,13 @@ impl GenericShader { }, }; - GenericShader { - graphics_pipeline: Some(Arc::new(GraphicsPipeline::start() + graphics_pipeline: + Some(Arc::new(GraphicsPipeline::start() .vertex_input(SingleBufferDefinition::::new()) - .vertex_shader(vertex_entry_point.clone().unwrap(), ShaderSpecializationConstants { + .vertex_shader(vertex_entry_point.unwrap(), ShaderSpecializationConstants { first_constant: 0, second_constant: 0, third_constant: 0.0, @@ -234,7 +297,7 @@ impl GenericShader { // Use a resizable viewport set to draw over the entire window .viewports_dynamic_scissors_irrelevant(1) - .fragment_shader(frag_entry_point.clone().unwrap(), ShaderSpecializationConstants { + .fragment_shader(fragment_entry_point.unwrap(), ShaderSpecializationConstants { first_constant: 0, second_constant: 0, third_constant: 0.0, @@ -242,6 +305,7 @@ impl GenericShader { .depth_stencil(stencil) + // 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()) diff --git a/src/canvas/canvas_state.rs b/src/canvas/canvas_state.rs index 34d27c13..9dfa4a9c 100644 --- a/src/canvas/canvas_state.rs +++ b/src/canvas/canvas_state.rs @@ -1,5 +1,5 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use vulkano::buffer::{BufferAccess, BufferUsage, ImmutableBuffer, CpuAccessibleBuffer}; use std::sync::Arc; use vulkano::format::{ClearValue, Format, R8Unorm}; @@ -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::{GenericShader, CanvasShaderHandle, CompiledGraphicsPipelineHandle, CompiledGraphicsPipeline}; +use crate::canvas::canvas_shader::{GenericShader, CanvasShaderHandle, CompiledGraphicsPipelineHandle, CompiledGraphicsPipeline, ShaderType}; use crate::canvas::canvas_buffer::{CanvasImage, CanvasTexture, CanvasTextCache}; use crate::util::vertex_3d::Vertex3D; use vulkano::pipeline::depth_stencil::{StencilFaceFlags, DynamicStencilValue}; @@ -51,14 +51,6 @@ pub trait Drawable { } } -/// Legacy ShaderType enum for single type shaders. -#[derive(PartialEq, Eq, Hash, Clone)] -pub enum ShaderType { - SOLID = 0, - TEXTURED = 1, - IMAGE = 2, -} - /// Typed wrapper for a u32 texture handle (index id) #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasTextureHandle { @@ -344,7 +336,6 @@ impl CanvasState { /// Takes physical and capabilities as we don't store that in Canvas pub fn load_shader(&mut self, filename: String, - shader_type: ShaderType, physical: PhysicalDevice, capabilities: Capabilities) -> Option> { diff --git a/src/compute/compu_buffer.rs b/src/compute/compu_buffer.rs index 2fa9ac63..9e46c268 100644 --- a/src/compute/compu_buffer.rs +++ b/src/compute/compu_buffer.rs @@ -6,6 +6,7 @@ use vulkano::descriptor::pipeline_layout::PipelineLayout; use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet, PersistentDescriptorSetBuf}; use image::ImageBuffer; use image::Rgba; +use shade_runner::Layout; #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CompuBufferHandle { @@ -68,8 +69,8 @@ impl CompuBuffers { self.dimensions } - pub fn get_descriptor_set(&self, compute_pipeline: std::sync::Arc>>) - -> Arc>>, ((((), + pub fn get_descriptor_set(&self, compute_pipeline: std::sync::Arc>>) + -> Arc>>, ((((), PersistentDescriptorSetBuf>>), PersistentDescriptorSetBuf>>), PersistentDescriptorSetBuf>>)>> { diff --git a/src/compute/compu_kernel.rs b/src/compute/compu_kernel.rs index e6789475..9e2cc852 100644 --- a/src/compute/compu_kernel.rs +++ b/src/compute/compu_kernel.rs @@ -5,7 +5,7 @@ use std::ffi::CStr; use std::path::PathBuf; use shade_runner as sr; use vulkano::descriptor::pipeline_layout::PipelineLayout; -use shade_runner::{CompileError, FragLayout, FragInput, FragOutput, VertInput, VertOutput, VertLayout, CompiledShaders, Entry}; +use shade_runner::{CompileError, Layout, Input, Output, CompiledShaders, Entry, CompiledShader}; use shaderc::CompileOptions; use vulkano::pipeline::shader::{ShaderModule, GraphicsEntryPoint, SpecializationConstants, SpecializationMapEntry}; use crate::compute::compu_buffer::{CompuBuffers, CompuBufferHandle}; @@ -20,12 +20,12 @@ pub struct CompuKernel { handle: Arc, - compute_pipeline: Option>>>, + compute_pipeline: Option>>>, compute_kernel_path: PathBuf, name: String, - shader: CompiledShaders, + shader: CompiledShader, entry: Entry, shader_module: Arc, device: Arc, @@ -61,7 +61,7 @@ impl CompuKernel { .expect("Failed to parse"); let shader_module = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.compute) + vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.spriv) }.unwrap(); @@ -82,7 +82,7 @@ impl CompuKernel { } } - pub fn get_pipeline(&mut self) -> std::sync::Arc>> { + pub fn get_pipeline(&mut self) -> std::sync::Arc>> { match self.compute_pipeline.clone() { Some(t) => t, @@ -91,7 +91,7 @@ impl CompuKernel { unsafe { ComputePipeline::new(self.device.clone(), &self.shader_module.compute_entry_point( CStr::from_bytes_with_nul_unchecked(b"main\0"), - self.entry.compute_layout.clone()), &self.specialization_constants, + self.entry.layout.clone()), &self.specialization_constants, ).unwrap() } })); @@ -100,11 +100,11 @@ impl CompuKernel { } } - pub fn recompile_kernel(&mut self) -> std::sync::Arc>> { + pub fn recompile_kernel(&mut self) -> std::sync::Arc>> { self.compile_kernel(String::from(self.compute_kernel_path.clone().to_str().unwrap())) } - pub fn compile_kernel(&mut self, filename: String) -> std::sync::Arc>> { + pub fn compile_kernel(&mut self, filename: String) -> std::sync::Arc>> { let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap(); self.compute_kernel_path = CompuKernel::get_path(filename); @@ -118,7 +118,7 @@ impl CompuKernel { .expect("Failed to parse"); self.shader_module = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &self.shader.compute) + vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &self.shader.spriv) }.unwrap(); self.get_pipeline() diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index 33623eba..3c37efa4 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -11,12 +11,12 @@ use winit::Window; use crate::compute::compu_state::CompuState; use vulkano::image::ImageUsage; use crate::compute::compu_frame::CompuFrame; -use crate::canvas::canvas_state::{CanvasState, CanvasTextureHandle, CanvasImageHandle, ShaderType}; +use crate::canvas::canvas_state::{CanvasState, CanvasTextureHandle, CanvasImageHandle}; 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, CompiledGraphicsPipeline, CompiledGraphicsPipelineHandle}; +use crate::canvas::canvas_shader::{CanvasShaderHandle, CompiledGraphicsPipeline, CompiledGraphicsPipelineHandle, ShaderType}; use vulkano::pipeline::depth_stencil::{DynamicStencilValue, StencilFaceFlags}; /// VKProcessor holds the vulkan instance information, the swapchain, and the compute and canvas states @@ -155,9 +155,9 @@ impl<'a> VkProcessor<'a> { /// 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"), ShaderType::SOLID, self.physical.clone(), self.capabilities.clone()); - self.canvas.load_shader(String::from("simple_texture"), ShaderType::TEXTURED, self.physical.clone(), self.capabilities.clone()); - self.canvas.load_shader(String::from("simple_image"), ShaderType::IMAGE, self.physical.clone(), self.capabilities.clone()); + 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()); + self.canvas.load_shader(String::from("simple_image"), self.physical.clone(), self.capabilities.clone()); } /// O(n) Lookup for the matching texture string