|
|
|
@ -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,83 +127,135 @@ 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())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl GenericShader {
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
/// 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 {
|
|
|
|
|
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<GraphicsEntryPoint<
|
|
|
|
|
ShaderSpecializationConstants,
|
|
|
|
|
Input,
|
|
|
|
|
Output,
|
|
|
|
|
Layout>> {
|
|
|
|
|
|
|
|
|
|
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<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(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
/// This will explode when the shader does not want to compile
|
|
|
|
|
pub fn new(filename: String,
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
let vertex_shader_module: Arc<ShaderModule> = 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<GraphicsEntryPoint<ShaderSpecializationConstants,Input,Output,Layout>>
|
|
|
|
|
= None;
|
|
|
|
|
let mut fragment_entry_point : Option<GraphicsEntryPoint<ShaderSpecializationConstants,Input,Output,Layout>>
|
|
|
|
|
= 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<ShaderModule> = 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<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 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::<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())
|
|
|
|
|