librashader_reflect/back/
mod.rs

1#[cfg(all(target_os = "windows", feature = "dxil"))]
2pub mod dxil;
3pub mod glsl;
4pub mod hlsl;
5pub mod msl;
6pub mod spirv;
7pub mod targets;
8pub mod wgsl;
9
10use crate::back::targets::OutputTarget;
11use crate::error::{ShaderCompileError, ShaderReflectError};
12use crate::reflect::semantics::ShaderSemantics;
13use crate::reflect::{ReflectShader, ShaderReflection};
14use std::fmt::Debug;
15
16/// The output of the shader compiler.
17#[derive(Debug)]
18pub struct ShaderCompilerOutput<T, Context = ()> {
19    /// The output for the vertex shader.
20    pub vertex: T,
21    /// The output for the fragment shader.
22    pub fragment: T,
23    /// Additional context provided by the shader compiler.
24    pub context: Context,
25}
26
27/// A trait for objects that can be compiled into a shader.
28pub trait CompileShader<T: OutputTarget> {
29    /// Options provided to the compiler.
30    type Options;
31    /// Additional context returned by the compiler after compilation.
32    type Context;
33
34    /// Consume the object and return the compiled output of the shader.
35    ///
36    /// The shader should either be reflected or validated as
37    /// [ReflectShader] before being compiled, or the results may not be valid.
38    fn compile(
39        self,
40        options: Self::Options,
41    ) -> Result<ShaderCompilerOutput<T::Output, Self::Context>, ShaderCompileError>;
42
43    /// Consume the object and return the compiled output of the shader.
44    ///
45    /// This is an internal implementation detail for stable building without TAIT,
46    /// to allow delegation when Self is unsized (i.e. dyn CompileReflectShader).
47    #[doc(hidden)]
48    fn compile_boxed(
49        self: Box<Self>,
50        options: Self::Options,
51    ) -> Result<ShaderCompilerOutput<T::Output, Self::Context>, ShaderCompileError>;
52}
53
54/// Marker trait for combinations of targets and compilations that can be reflected and compiled
55/// successfully.
56///
57/// This trait is automatically implemented for reflected outputs that have [`FromCompilation`] implement
58/// for a given target that also implement [`CompileShader`] for that target.
59pub trait CompileReflectShader<T: OutputTarget, C, S>:
60    CompileShader<
61        T,
62        Options = <T as FromCompilation<C, S>>::Options,
63        Context = <T as FromCompilation<C, S>>::Context,
64    > + ReflectShader
65where
66    T: FromCompilation<C, S>,
67{
68}
69
70impl<T, C, O, S> CompileReflectShader<T, C, S> for O
71where
72    T: OutputTarget,
73    T: FromCompilation<C, S>,
74    O: ReflectShader,
75    O: CompileShader<
76        T,
77        Options = <T as FromCompilation<C, S>>::Options,
78        Context = <T as FromCompilation<C, S>>::Context,
79    >,
80{
81}
82
83impl<T, E> CompileShader<E> for CompilerBackend<T>
84where
85    T: CompileShader<E>,
86    E: OutputTarget,
87{
88    type Options = T::Options;
89    type Context = T::Context;
90
91    fn compile(
92        self,
93        options: Self::Options,
94    ) -> Result<ShaderCompilerOutput<E::Output, Self::Context>, ShaderCompileError> {
95        self.backend.compile(options)
96    }
97
98    fn compile_boxed(
99        self: Box<Self>,
100        options: Self::Options,
101    ) -> Result<ShaderCompilerOutput<E::Output, Self::Context>, ShaderCompileError> {
102        self.backend.compile(options)
103    }
104}
105
106/// A trait for reflectable compilations that can be transformed
107/// into an object ready for reflection or compilation.
108///
109/// `T` is the compiled reflectable form of the shader.
110/// `S` is the semantics under which the shader is reflected.
111///
112/// librashader currently supports two semantics, [`SpirvCross`](crate::reflect::cross::SpirvCross)
113pub trait FromCompilation<T, S> {
114    /// The target that the transformed object is expected to compile for.
115    type Target: OutputTarget;
116    /// Options provided to the compiler.
117    type Options;
118    /// Additional context returned by the compiler after compilation.
119    type Context;
120
121    /// The output type after conversion.
122    type Output: CompileShader<Self::Target, Context = Self::Context, Options = Self::Options>
123        + ReflectShader;
124
125    /// Tries to convert the input object into an object ready for compilation.
126    fn from_compilation(compile: T) -> Result<CompilerBackend<Self::Output>, ShaderReflectError>;
127}
128
129/// A wrapper for a compiler backend.
130pub struct CompilerBackend<T> {
131    pub(crate) backend: T,
132}
133
134impl<T> ReflectShader for CompilerBackend<T>
135where
136    T: ReflectShader,
137{
138    fn reflect(
139        &mut self,
140        pass_number: usize,
141        semantics: &ShaderSemantics,
142    ) -> Result<ShaderReflection, ShaderReflectError> {
143        self.backend.reflect(pass_number, semantics)
144    }
145
146    fn validate(&mut self) -> Result<(), ShaderReflectError> {
147        self.backend.validate()
148    }
149}
150
151impl<T: ReflectShader + ?Sized> ReflectShader for Box<T> {
152    fn reflect(
153        &mut self,
154        pass_number: usize,
155        semantics: &ShaderSemantics,
156    ) -> Result<ShaderReflection, ShaderReflectError> {
157        (**self).reflect(pass_number, semantics)
158    }
159
160    fn validate(&mut self) -> Result<(), ShaderReflectError> {
161        (**self).validate()
162    }
163}
164
165impl<O, T> CompileShader<T> for Box<O>
166where
167    O: CompileShader<T> + ?Sized,
168    T: OutputTarget,
169{
170    type Options = O::Options;
171    type Context = O::Context;
172
173    fn compile(
174        self,
175        options: Self::Options,
176    ) -> Result<ShaderCompilerOutput<T::Output, Self::Context>, ShaderCompileError> {
177        O::compile_boxed(self, options)
178    }
179
180    fn compile_boxed(
181        self: Box<Self>,
182        options: Self::Options,
183    ) -> Result<ShaderCompilerOutput<T::Output, Self::Context>, ShaderCompileError> {
184        self.compile(options)
185    }
186}
187
188#[cfg(test)]
189mod test {
190    use crate::front::{Glslang, ShaderInputCompiler};
191    use librashader_preprocess::ShaderSource;
192
193    pub fn test() {
194        let result = ShaderSource::load("../test/basic.slang").unwrap();
195        let _cross = Glslang::compile(&result).unwrap();
196    }
197}