use crate::prelude::*; use anyhow::{Context, Result}; use std::fs::File; use std::io::Read; use std::sync::Arc; #[allow(clippy::cast_ptr_alignment)] #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum ShaderType { None, Vertex, Fragment, Geometry, TesselationControl, TesselationEvaluation, Compute, RayGeneration, ClosestHit, Miss, AnyHit, Intersection, } impl From for ShaderType { fn from(value: u8) -> Self { match value { 0 => Self::None, 1 => Self::Vertex, 2 => Self::Fragment, 3 => Self::Geometry, 4 => Self::TesselationControl, 5 => Self::TesselationEvaluation, 6 => Self::Compute, 7 => Self::RayGeneration, 8 => Self::ClosestHit, 9 => Self::Miss, 10 => Self::AnyHit, 11 => Self::Intersection, _ => panic!("can't convert ShaderType from {}", value), } } } impl Default for ShaderType { fn default() -> Self { ShaderType::None } } pub trait VertexInputDescription: ReprC { fn bindings() -> Vec { vec![VkVertexInputBindingDescription { binding: 0, stride: std::mem::size_of::() as u32, inputRate: VK_VERTEX_INPUT_RATE_VERTEX, }] } fn attributes() -> Vec; } pub trait PipelineStageInfo { fn pipeline_stage_info(&self) -> VkPipelineShaderStageCreateInfo; } macro_rules! impl_pipeline_stage_info { ($func:ident, $type:ident) => { impl PipelineStageInfo for ShaderModule<{ ShaderType::$type as u8 }> { fn pipeline_stage_info(&self) -> VkPipelineShaderStageCreateInfo { VkPipelineShaderStageCreateInfo::$func(self.shader_module) } } }; } #[derive(Debug)] pub struct ShaderModule { device: Arc, shader_module: VkShaderModule, } impl ShaderModule { pub fn new(device: Arc, path: &str) -> Result>> { let code = Self::shader_code(path)?; Self::from_slice(device, code.as_slice()) } pub fn from_slice(device: Arc, code: &[u8]) -> Result>> { let shader_module_ci = VkShaderModuleCreateInfo::new(VK_SHADER_MODULE_CREATE_NULL_BIT, code); let shader_module = device.create_shader_module(&shader_module_ci)?; Ok(Arc::new(ShaderModule { device, shader_module, })) } fn shader_code(path: &str) -> Result> { let mut file = File::open(path).with_context({ let path = path.to_string(); || path })?; let mut code: Vec = Vec::new(); file.read_to_end(&mut code)?; Ok(code) } } impl_pipeline_stage_info!(vertex, Vertex); impl_pipeline_stage_info!(geometry, Geometry); impl_pipeline_stage_info!(tesselation_control, TesselationControl); impl_pipeline_stage_info!(tesselation_evaluation, TesselationEvaluation); impl_pipeline_stage_info!(fragment, Fragment); impl_pipeline_stage_info!(compute, Compute); impl_pipeline_stage_info!(any_hit, AnyHit); impl_pipeline_stage_info!(intersection, Intersection); impl_pipeline_stage_info!(closest_hit, ClosestHit); impl_pipeline_stage_info!(ray_generation, RayGeneration); impl_pipeline_stage_info!(miss, Miss); impl VulkanDevice for ShaderModule { fn device(&self) -> &Arc { &self.device } } impl_vk_handle!(ShaderModule, VkShaderModule, shader_module); impl Drop for ShaderModule { fn drop(&mut self) { self.device.destroy_shader_module(self.shader_module); } } pub trait AddSpecializationConstant { fn add(&mut self, value: T, id: u32); } pub struct SpecializationConstants { // store data as raw bytes data: Vec, entries: Vec, info: VkSpecializationInfo, } impl SpecializationConstants { pub fn new() -> Self { let mut me = SpecializationConstants { data: Vec::new(), entries: Vec::new(), info: VkSpecializationInfo::empty(), }; me.info.set_data(&me.data); me.info.set_map_entries(&me.entries); me } pub fn vk_handle(&self) -> &VkSpecializationInfo { &self.info } } macro_rules! impl_add_specialization_constant { ($($type: ty),+) => { $( impl AddSpecializationConstant<$type> for SpecializationConstants { fn add(&mut self, value: $type, id: u32) { let bytes = value.to_ne_bytes(); self.entries.push(VkSpecializationMapEntry { constantID: id, offset: self.data.len() as u32, size: bytes.len(), }); self.data.extend(&bytes); } } )+ }; } impl_add_specialization_constant!(f32, f64, u64, i64, u32, i32, u16, i16, u8, i8, usize, isize);