use crate::back::targets::OutputTarget; use crate::back::{CompilerBackend, FromCompilation}; use crate::error::{ShaderCompileError, ShaderReflectError}; use crate::front::{ShaderInputCompiler, ShaderReflectObject}; use crate::reflect::semantics::{ Semantic, ShaderSemantics, TextureSemantics, UniformSemantic, UniqueSemantics, }; use librashader_common::map::{FastHashMap, ShortString}; use librashader_preprocess::{PreprocessError, ShaderSource}; use librashader_presets::{ShaderPassConfig, TextureConfig}; /// Artifacts of a reflected and compiled shader pass. /// /// The [`CompileReflectShader`](crate::back::CompileReflectShader) trait allows you to name /// the type of compiler artifact returned by a pair of output shader target and compilation /// instance as a TAIT like so. /// /// ```rust /// #![feature(type_alias_impl_trait)] /// use librashader_reflect::back::CompileReflectShader; /// use librashader_reflect::back::targets::{GLSL, SPIRV}; /// use librashader_reflect::front::SpirvCompilation; /// use librashader_reflect::reflect::cross::SpirvCross; /// use librashader_reflect::reflect::presets::ShaderPassArtifact; /// /// type VulkanPassMeta = ShaderPassArtifact>; /// ``` /// /// This allows a runtime to not name the backing type of the compiled artifact if not necessary. pub type ShaderPassArtifact = (ShaderPassConfig, ShaderSource, CompilerBackend); impl CompilePresetTarget for T {} /// Trait for target shading languages that can compile output with /// shader preset metdata. pub trait CompilePresetTarget: OutputTarget { /// Compile passes of a shader preset given the applicable /// shader output target, compilation type, and resulting error. fn compile_preset_passes( passes: Vec, textures: &[TextureConfig], ) -> Result< ( Vec>::Output>>, ShaderSemantics, ), E, > where I: ShaderReflectObject, Self: Sized, Self: FromCompilation, I::Compiler: ShaderInputCompiler, E: From, E: From, E: From, { compile_preset_passes::(passes, textures) } } /// Compile passes of a shader preset given the applicable /// shader output target, compilation type, and resulting error. fn compile_preset_passes( passes: Vec, textures: &[TextureConfig], ) -> Result< ( Vec>::Output>>, ShaderSemantics, ), E, > where I: ShaderReflectObject, T: OutputTarget, T: FromCompilation, I::Compiler: ShaderInputCompiler, E: From, E: From, E: From, { let mut uniform_semantics: FastHashMap = Default::default(); let mut texture_semantics: FastHashMap> = Default::default(); let passes = passes .into_iter() .map(|shader| { let source: ShaderSource = ShaderSource::load(&shader.name)?; let compiled = I::Compiler::compile(&source)?; let reflect = T::from_compilation(compiled)?; for parameter in source.parameters.values() { uniform_semantics.insert( parameter.id.clone(), UniformSemantic::Unique(Semantic { semantics: UniqueSemantics::FloatParameter, index: (), }), ); } Ok::<_, E>((shader, source, reflect)) }) .collect::)>, E>>()?; for details in &passes { insert_pass_semantics(&mut uniform_semantics, &mut texture_semantics, &details.0) } insert_lut_semantics(textures, &mut uniform_semantics, &mut texture_semantics); let semantics = ShaderSemantics { uniform_semantics, texture_semantics, }; Ok((passes, semantics)) } /// Insert the available semantics for the input pass config into the provided semantic maps. fn insert_pass_semantics( uniform_semantics: &mut FastHashMap, texture_semantics: &mut FastHashMap>, config: &ShaderPassConfig, ) { let Some(alias) = &config.alias else { return; }; // Ignore empty aliases if alias.trim().is_empty() { return; } let index = config.id as usize; // PassOutput texture_semantics.insert( alias.clone(), Semantic { semantics: TextureSemantics::PassOutput, index, }, ); let mut alias_size = alias.clone(); alias_size.push_str("Size"); uniform_semantics.insert( alias_size, UniformSemantic::Texture(Semantic { semantics: TextureSemantics::PassOutput, index, }), ); let mut alias_feedback = alias.clone(); alias_feedback.push_str("Feedback"); // PassFeedback texture_semantics.insert( alias_feedback, Semantic { semantics: TextureSemantics::PassFeedback, index, }, ); let mut alias_feedback_size = alias.clone(); alias_feedback_size.push_str("FeedbackSize"); uniform_semantics.insert( alias_feedback_size, UniformSemantic::Texture(Semantic { semantics: TextureSemantics::PassFeedback, index, }), ); } /// Insert the available semantics for the input texture config into the provided semantic maps. fn insert_lut_semantics( textures: &[TextureConfig], uniform_semantics: &mut FastHashMap, texture_semantics: &mut FastHashMap>, ) { for (index, texture) in textures.iter().enumerate() { let mut size_semantic = texture.name.clone(); size_semantic.push_str("Size"); texture_semantics.insert( texture.name.clone(), Semantic { semantics: TextureSemantics::User, index, }, ); uniform_semantics.insert( size_semantic, UniformSemantic::Texture(Semantic { semantics: TextureSemantics::User, index, }), ); } }