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, Vertex2D};
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct CanvasShaderHandle {
pub handle: u32
}
#[derive(Clone)]
pub struct CanvasShader {
graphics_pipeline: Option<Arc<dyn GraphicsPipelineAbstract + Sync + Send>>,
device: Arc<Device>,
pub(crate) handle: Arc<CanvasShaderHandle>,
pub(crate) name: String,
}
impl 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)
}
pub fn get_pipeline(&self) -> Arc<dyn GraphicsPipelineAbstract + Sync + Send> {
self.graphics_pipeline.clone().unwrap()
}
pub fn new_colored(filename: String,
capabilities: Capabilities,
queue: Arc<Queue>,
physical: PhysicalDevice,
device: Arc<Device>,
handle: Arc<CanvasShaderHandle>,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,) -> CanvasShader {
let format = capabilities.supported_formats[0].0;
let filenames = CanvasShader::get_path(filename.clone());
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 = CanvasShader::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 = CanvasShader::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 = 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"),
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: {
color: {
load: Clear,
store: Store,
format: format,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap());
CanvasShader {
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_list()
.viewports_dynamic_scissors_irrelevant(1)
.fragment_shader(frag_entry_point.clone().unwrap(), ShaderSpecializationConstants {
first_constant: 0,
second_constant: 0,
third_constant: 0.0,
})
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
.build(device.clone())
.unwrap())),
device: device,
handle: handle.clone(),
name: filename.clone(),
}
}
pub fn new_textured(filename: String,
capabilities: Capabilities,
queue: Arc<Queue>,
physical: PhysicalDevice,
device: Arc<Device>,
handle: Arc<CanvasShaderHandle>,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,) -> CanvasShader {
let format = capabilities.supported_formats[0].0;
let filenames = CanvasShader::get_path(filename.clone());
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 = CanvasShader::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 = CanvasShader::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 = 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"),
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))
};
CanvasShader {
graphics_pipeline: Some(Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex2D>()
.vertex_shader(vertex_entry_point.clone().unwrap(), ShaderSpecializationConstants {
first_constant: 0,
second_constant: 0,
third_constant: 0.0,
})
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.fragment_shader(frag_entry_point.clone().unwrap(), ShaderSpecializationConstants {
first_constant: 0,
second_constant: 0,
third_constant: 0.0,
})
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
.build(device.clone())
.unwrap())),
device: device,
handle: handle.clone(),
name: filename.clone(),
}
}
}
#[repr(C)]
#[derive(Default, Debug, Clone)]
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
}
}