You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Trac3r-rust/src/util/shader_kernels.rs

232 lines
7.6 KiB

use vulkano::device::{Device, Queue};
use vulkano::instance::{PhysicalDevice, QueueFamily};
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::swapchain::{Capabilities};
use crate::vertex_2d::ColoredVertex2D;
/*
Shaderkernel holds the pipeline and render pass for the inputted shader source
*/
#[derive(Clone)]
pub struct ShaderKernels {
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
graphics_pipeline: Option<Arc<dyn GraphicsPipelineAbstract + Sync + Send>>,
device: Arc<Device>,
}
impl ShaderKernels {
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)
}
pub fn get_pipeline(&mut self) -> Arc<dyn GraphicsPipelineAbstract + Sync + Send> {
self.graphics_pipeline.clone().unwrap()
}
pub fn new(filename: String,
capabilities: Capabilities,
queue: Arc<Queue>,
physical: PhysicalDevice,
device: Arc<Device>) -> ShaderKernels {
let format = capabilities.supported_formats[0].0;
let filenames = ShaderKernels::get_path(filename.clone());
// TODO: better compile message, run til successful compile
let shader = sr::load(filenames.0, filenames.1)
.expect("Shader didn't compile");
let vulkano_entry =
sr::parse(&shader)
.expect("failed to parse");
let fragment_shader_module: Arc<ShaderModule> = unsafe {
let filenames1 = ShaderKernels::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())
}.unwrap();
let vertex_shader_module: Arc<ShaderModule> = unsafe {
let filenames1 = ShaderKernels::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())
}.unwrap();
let filenames = ShaderKernels::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"),
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 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: <ty>` 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,
// TODO:
samples: 1,
}
},
pass: {
// We use the attachment named `color` as the one and only color attachment.
color: [color],
//color: [],
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil: {}
}
).unwrap());
ShaderKernels {
graphics_pipeline: Some(Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<ColoredVertex2D>()
.vertex_shader(vertex_entry_point.clone().unwrap(), ShaderSpecializationConstants {
first_constant: 0,
second_constant: 0,
third_constant: 0.0,
})
.triangle_fan()
// Use a resizable viewport set to draw over the entire window
.viewports_dynamic_scissors_irrelevant(1)
.fragment_shader(frag_entry_point.clone().unwrap(), ShaderSpecializationConstants {
first_constant: 0,
second_constant: 0,
third_constant: 0.0,
})
// 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())
.build(device.clone())
.unwrap())),
device: device,
render_pass: render_pass,
}
}
}
#[repr(C)]
#[derive(Default, Debug, Clone)]
// TODO: This needs to be duplicated and moved into their respective containers shaderkenrels copute
struct ShaderSpecializationConstants {
first_constant: i32,
second_constant: u32,
third_constant: f32,
}
unsafe impl SpecializationConstants for ShaderSpecializationConstants {
fn descriptors() -> &'static [SpecializationMapEntry] {
static DESCRIPTORS: [SpecializationMapEntry; 3] = [
SpecializationMapEntry {
constant_id: 0,
offset: 0,
size: 4,
},
SpecializationMapEntry {
constant_id: 1,
offset: 4,
size: 4,
},
SpecializationMapEntry {
constant_id: 2,
offset: 8,
size: 4,
},
];
&DESCRIPTORS
}
}