2023-01-19 13:58:13 +11:00
|
|
|
use crate::back::targets::OutputTarget;
|
2023-01-19 17:06:17 +11:00
|
|
|
use crate::back::{CompilerBackend, FromCompilation};
|
2023-01-19 13:58:13 +11:00
|
|
|
use crate::error::{ShaderCompileError, ShaderReflectError};
|
2024-02-11 10:54:57 +11:00
|
|
|
use crate::front::{ShaderInputCompiler, ShaderReflectObject};
|
2023-01-19 13:58:13 +11:00
|
|
|
use crate::reflect::semantics::{
|
|
|
|
Semantic, ShaderSemantics, TextureSemantics, UniformSemantic, UniqueSemantics,
|
|
|
|
};
|
2023-01-19 16:37:37 +11:00
|
|
|
use librashader_preprocess::{PreprocessError, ShaderSource};
|
|
|
|
use librashader_presets::{ShaderPassConfig, TextureConfig};
|
2023-01-19 13:58:13 +11:00
|
|
|
use rustc_hash::FxHashMap;
|
|
|
|
|
|
|
|
/// Artifacts of a reflected and compiled shader pass.
|
2023-01-20 10:44:08 +11:00
|
|
|
///
|
|
|
|
/// 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;
|
2024-02-11 12:46:35 +11:00
|
|
|
/// use librashader_reflect::back::targets::{GLSL, SPIRV};
|
2024-02-11 09:47:05 +11:00
|
|
|
/// use librashader_reflect::front::SpirvCompilation;
|
2024-02-11 12:46:35 +11:00
|
|
|
/// use librashader_reflect::reflect::cross::SpirvCross;
|
2023-01-20 10:44:08 +11:00
|
|
|
/// use librashader_reflect::reflect::presets::ShaderPassArtifact;
|
|
|
|
///
|
2024-02-14 09:37:48 +11:00
|
|
|
/// type VulkanPassMeta = ShaderPassArtifact<impl CompileReflectShader<SPIRV, SpirvCompilation, SpirvCross>>;
|
2023-01-20 10:44:08 +11:00
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// This allows a runtime to not name the backing type of the compiled artifact if not necessary.
|
|
|
|
pub type ShaderPassArtifact<T> = (ShaderPassConfig, ShaderSource, CompilerBackend<T>);
|
2023-01-19 13:58:13 +11:00
|
|
|
|
2023-01-20 10:44:08 +11:00
|
|
|
impl<T: OutputTarget> CompilePresetTarget for T {}
|
2023-01-19 13:58:13 +11:00
|
|
|
|
|
|
|
/// Trait for target shading languages that can compile output with
|
|
|
|
/// shader preset metdata.
|
2023-01-20 10:44:08 +11:00
|
|
|
pub trait CompilePresetTarget: OutputTarget {
|
2023-01-19 13:58:13 +11:00
|
|
|
/// Compile passes of a shader preset given the applicable
|
|
|
|
/// shader output target, compilation type, and resulting error.
|
2024-02-14 09:37:48 +11:00
|
|
|
fn compile_preset_passes<I, R, E>(
|
2023-01-19 13:58:13 +11:00
|
|
|
passes: Vec<ShaderPassConfig>,
|
|
|
|
textures: &[TextureConfig],
|
2023-01-19 16:37:37 +11:00
|
|
|
) -> Result<
|
2023-01-19 13:58:13 +11:00
|
|
|
(
|
2024-02-11 12:46:35 +11:00
|
|
|
Vec<ShaderPassArtifact<<Self as FromCompilation<I, R>>::Output>>,
|
2023-01-19 13:58:13 +11:00
|
|
|
ShaderSemantics,
|
|
|
|
),
|
|
|
|
E,
|
|
|
|
>
|
2023-01-19 16:37:37 +11:00
|
|
|
where
|
2024-02-11 09:47:05 +11:00
|
|
|
I: ShaderReflectObject,
|
2023-01-19 16:37:37 +11:00
|
|
|
Self: Sized,
|
2024-02-11 12:46:35 +11:00
|
|
|
Self: FromCompilation<I, R>,
|
2024-02-14 09:37:48 +11:00
|
|
|
I::Compiler: ShaderInputCompiler<I>,
|
2023-01-19 16:37:37 +11:00
|
|
|
E: From<PreprocessError>,
|
|
|
|
E: From<ShaderReflectError>,
|
|
|
|
E: From<ShaderCompileError>,
|
|
|
|
{
|
2024-02-14 09:37:48 +11:00
|
|
|
compile_preset_passes::<Self, I, R, E>(passes, textures)
|
2023-01-19 13:58:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compile passes of a shader preset given the applicable
|
|
|
|
/// shader output target, compilation type, and resulting error.
|
2024-02-14 09:37:48 +11:00
|
|
|
fn compile_preset_passes<T, I, R, E>(
|
2023-01-19 13:58:13 +11:00
|
|
|
passes: Vec<ShaderPassConfig>,
|
|
|
|
textures: &[TextureConfig],
|
|
|
|
) -> Result<
|
|
|
|
(
|
2024-02-11 12:46:35 +11:00
|
|
|
Vec<ShaderPassArtifact<<T as FromCompilation<I, R>>::Output>>,
|
2023-01-19 13:58:13 +11:00
|
|
|
ShaderSemantics,
|
|
|
|
),
|
|
|
|
E,
|
|
|
|
>
|
2023-01-19 16:37:37 +11:00
|
|
|
where
|
2024-02-11 09:47:05 +11:00
|
|
|
I: ShaderReflectObject,
|
2023-01-19 16:37:37 +11:00
|
|
|
T: OutputTarget,
|
2024-02-11 12:46:35 +11:00
|
|
|
T: FromCompilation<I, R>,
|
2024-02-14 09:37:48 +11:00
|
|
|
I::Compiler: ShaderInputCompiler<I>,
|
2023-01-19 16:37:37 +11:00
|
|
|
E: From<PreprocessError>,
|
|
|
|
E: From<ShaderReflectError>,
|
|
|
|
E: From<ShaderCompileError>,
|
2023-01-19 13:58:13 +11:00
|
|
|
{
|
|
|
|
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
|
|
|
|
let mut texture_semantics: FxHashMap<String, Semantic<TextureSemantics>> = Default::default();
|
|
|
|
|
|
|
|
let passes = passes
|
|
|
|
.into_iter()
|
|
|
|
.map(|shader| {
|
|
|
|
let source: ShaderSource = ShaderSource::load(&shader.name)?;
|
|
|
|
|
2024-02-14 09:37:48 +11:00
|
|
|
let compiled = I::Compiler::compile(&source)?;
|
2023-01-19 13:58:13 +11:00
|
|
|
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::<Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>, E>>()?;
|
|
|
|
|
|
|
|
for details in &passes {
|
2023-01-19 16:37:37 +11:00
|
|
|
insert_pass_semantics(&mut uniform_semantics, &mut texture_semantics, &details.0)
|
2023-01-19 13:58:13 +11:00
|
|
|
}
|
2023-01-19 16:37:37 +11:00
|
|
|
insert_lut_semantics(textures, &mut uniform_semantics, &mut texture_semantics);
|
2023-01-19 13:58:13 +11:00
|
|
|
|
|
|
|
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 FxHashMap<String, UniformSemantic>,
|
|
|
|
texture_semantics: &mut FxHashMap<String, Semantic<TextureSemantics>>,
|
|
|
|
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,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
uniform_semantics.insert(
|
|
|
|
format!("{alias}Size"),
|
|
|
|
UniformSemantic::Texture(Semantic {
|
|
|
|
semantics: TextureSemantics::PassOutput,
|
|
|
|
index,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
// PassFeedback
|
|
|
|
texture_semantics.insert(
|
|
|
|
format!("{alias}Feedback"),
|
|
|
|
Semantic {
|
|
|
|
semantics: TextureSemantics::PassFeedback,
|
|
|
|
index,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
uniform_semantics.insert(
|
|
|
|
format!("{alias}FeedbackSize"),
|
|
|
|
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 FxHashMap<String, UniformSemantic>,
|
|
|
|
texture_semantics: &mut FxHashMap<String, Semantic<TextureSemantics>>,
|
|
|
|
) {
|
|
|
|
for (index, texture) in textures.iter().enumerate() {
|
|
|
|
texture_semantics.insert(
|
|
|
|
texture.name.clone(),
|
|
|
|
Semantic {
|
|
|
|
semantics: TextureSemantics::User,
|
|
|
|
index,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
uniform_semantics.insert(
|
|
|
|
format!("{}Size", texture.name),
|
|
|
|
UniformSemantic::Texture(Semantic {
|
|
|
|
semantics: TextureSemantics::User,
|
|
|
|
index,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|