hitting this damn shader module again. Very unergonomic interface with the fact that the entry point doesn't just own the shadermodule

This commit is contained in:
2019-09-24 22:39:24 -07:00
parent 3db8eaf006
commit 5a888a4163
5 changed files with 145 additions and 89 deletions

View File

@@ -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<CompiledGraphicsPipelineHandle>;
fn get_pipeline(&self) -> Arc<dyn GraphicsPipelineAbstract + Sync + Send>;
fn recompile(self, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>)
-> Self where Self: Sized;
-> Self where Self: Sized;
}
/// Legacy ShaderType enum for single type shaders.
@@ -116,84 +127,136 @@ impl CompiledGraphicsPipeline for GenericShader {
fn recompile(self, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>) -> GenericShader {
GenericShader::new(self.name,
self.shader_types,
self.device,
self.handle,
render_pass.clone())
}
}
/*
Realistically, what should the API for this thing look like...
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.
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 {
pub fn ret(&self) -> Option<GraphicsEntryPoint<
ShaderSpecializationConstants,
Input,
Output,
Layout>> {
let compiled_shader = sr::load_vertex("dfqwefqwef")
.expect("Shader didn't compile");
let vulkano_entry =
sr::parse(&compiled_shader)
.expect("failed to parse");
let shader_module: Arc<ShaderModule> = 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(),
})
}
}
/// This will explode when the shader does not want to compile
pub fn new(filename: String,
shader_types: HashSet<ShaderType>,
device: Arc<Device>,
handle: Arc<CompiledGraphicsPipelineHandle>,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>) -> GenericShader {
let mut shader_types : HashSet<ShaderType> = vec![
ShaderType::VERTEX,
ShaderType::FRAGMENT,
].iter().cloned().collect();
let filenames = GenericShader::get_paths(filename.clone(), shader_types.clone());
// TODO: better compile message, run til successful compile
// let mut c = Vec::new();
let mut vertex_entry_point : Option<GraphicsEntryPoint<ShaderSpecializationConstants,Input,Output,Layout>>
= None;
let mut fragment_entry_point : Option<GraphicsEntryPoint<ShaderSpecializationConstants,Input,Output,Layout>>
= None;
for shader in filenames {
match shader.0 {
ShaderType::VERTEX => {
let shader = sr::load(filenames.0, filenames.1)
.expect("Shader didn't compile");
let compiled_shader = sr::load_vertex(shader.1)
.expect("Shader didn't compile");
let vulkano_entry =
sr::parse(&shader)
.expect("failed to parse");
}
ShaderType::FRAGMENT => {
let vulkano_entry =
sr::parse(&compiled_shader)
.expect("failed to parse");
}
ShaderType::GEOMETRY => {
let shader_module: Arc<ShaderModule> = unsafe {
ShaderModule::from_words(device.clone(), &compiled_shader.spriv.clone())
}.unwrap();
}
ShaderType::TESSELLATION => {
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<GraphicsEntryPoint<
ShaderSpecializationConstants,
Input,
Output,
Layout>> = 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 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()) }
_ => {}
};
// c.push((entry_point.unwrap().clone(), shader_module.clone()));
}
let fragment_shader_module: Arc<ShaderModule> = 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();
let vertex_shader_module: Arc<ShaderModule> = 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.vertex.clone())
}.unwrap();
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 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))
};
let stencil = DepthStencil {
depth_compare: Compare::Less,
depth_write: true,
@@ -218,13 +281,13 @@ impl GenericShader {
},
};
GenericShader {
graphics_pipeline: Some(Arc::new(GraphicsPipeline::start()
graphics_pipeline:
Some(Arc::new(GraphicsPipeline::start()
.vertex_input(SingleBufferDefinition::<Vertex3D>::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())

View File

@@ -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<Arc<CompiledGraphicsPipelineHandle>> {