librashader_cache/
compilation.rs1use librashader_preprocess::ShaderSource;
3#[cfg(all(target_os = "windows", feature = "d3d"))]
4use librashader_reflect::back::targets::DXIL;
5use librashader_reflect::back::targets::{GLSL, HLSL, SPIRV};
6
7use librashader_reflect::back::{CompilerBackend, FromCompilation};
8use librashader_reflect::error::{ShaderCompileError, ShaderReflectError};
9use librashader_reflect::front::{
10 Glslang, ShaderInputCompiler, ShaderReflectObject, SpirvCompilation,
11};
12
13pub struct CachedCompilation<T> {
14 compilation: T,
15}
16
17impl<T: ShaderReflectObject> ShaderReflectObject for CachedCompilation<T> {
18 type Compiler = T::Compiler;
19}
20
21impl<T: ShaderReflectObject + for<'de> serde::Deserialize<'de> + serde::Serialize + Clone>
22 ShaderInputCompiler<CachedCompilation<T>> for Glslang
23where
24 Glslang: ShaderInputCompiler<T>,
25{
26 fn compile(source: &ShaderSource) -> Result<CachedCompilation<T>, ShaderCompileError> {
27 let cache = crate::cache::internal::get_cache();
28
29 let Ok(cache) = cache else {
30 return Ok(CachedCompilation {
31 compilation: Glslang::compile(source)?,
32 });
33 };
34
35 let key = {
36 let mut hasher = blake3::Hasher::new();
37 hasher.update(source.vertex.as_bytes());
38 hasher.update(source.fragment.as_bytes());
39 let hash = hasher.finalize();
40 hash
41 };
42
43 let compilation = 'cached: {
44 if let Ok(Some(cached)) =
45 crate::cache::internal::get_blob(&cache, "spirv", key.as_bytes())
46 {
47 let decoded =
48 bincode::serde::decode_from_slice(&cached, bincode::config::standard())
49 .map(|(compilation, _)| CachedCompilation { compilation })
50 .ok();
51
52 if let Some(compilation) = decoded {
53 break 'cached compilation;
54 }
55 }
56
57 CachedCompilation {
58 compilation: Glslang::compile(source)?,
59 }
60 };
61
62 if let Ok(updated) =
63 bincode::serde::encode_to_vec(&compilation.compilation, bincode::config::standard())
64 {
65 let Ok(()) =
66 crate::cache::internal::set_blob(&cache, "spirv", key.as_bytes(), &updated)
67 else {
68 return Ok(compilation);
69 };
70 }
71
72 Ok(compilation)
73 }
74}
75
76#[cfg(all(target_os = "windows", feature = "d3d"))]
77impl<T> FromCompilation<CachedCompilation<SpirvCompilation>, T> for DXIL
78where
79 DXIL: FromCompilation<SpirvCompilation, T>,
80{
81 type Target = <DXIL as FromCompilation<SpirvCompilation, T>>::Target;
82 type Options = <DXIL as FromCompilation<SpirvCompilation, T>>::Options;
83 type Context = <DXIL as FromCompilation<SpirvCompilation, T>>::Context;
84 type Output = <DXIL as FromCompilation<SpirvCompilation, T>>::Output;
85
86 fn from_compilation(
87 compile: CachedCompilation<SpirvCompilation>,
88 ) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
89 DXIL::from_compilation(compile.compilation)
90 }
91}
92
93impl<T> FromCompilation<CachedCompilation<SpirvCompilation>, T> for HLSL
94where
95 HLSL: FromCompilation<SpirvCompilation, T>,
96{
97 type Target = <HLSL as FromCompilation<SpirvCompilation, T>>::Target;
98 type Options = <HLSL as FromCompilation<SpirvCompilation, T>>::Options;
99 type Context = <HLSL as FromCompilation<SpirvCompilation, T>>::Context;
100 type Output = <HLSL as FromCompilation<SpirvCompilation, T>>::Output;
101
102 fn from_compilation(
103 compile: CachedCompilation<SpirvCompilation>,
104 ) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
105 HLSL::from_compilation(compile.compilation)
106 }
107}
108
109impl<T> FromCompilation<CachedCompilation<SpirvCompilation>, T> for GLSL
110where
111 GLSL: FromCompilation<SpirvCompilation, T>,
112{
113 type Target = <GLSL as FromCompilation<SpirvCompilation, T>>::Target;
114 type Options = <GLSL as FromCompilation<SpirvCompilation, T>>::Options;
115 type Context = <GLSL as FromCompilation<SpirvCompilation, T>>::Context;
116 type Output = <GLSL as FromCompilation<SpirvCompilation, T>>::Output;
117
118 fn from_compilation(
119 compile: CachedCompilation<SpirvCompilation>,
120 ) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
121 GLSL::from_compilation(compile.compilation)
122 }
123}
124
125impl<T> FromCompilation<CachedCompilation<SpirvCompilation>, T> for SPIRV
126where
127 SPIRV: FromCompilation<SpirvCompilation, T>,
128{
129 type Target = <SPIRV as FromCompilation<SpirvCompilation, T>>::Target;
130 type Options = <SPIRV as FromCompilation<SpirvCompilation, T>>::Options;
131 type Context = <SPIRV as FromCompilation<SpirvCompilation, T>>::Context;
132 type Output = <SPIRV as FromCompilation<SpirvCompilation, T>>::Output;
133
134 fn from_compilation(
135 compile: CachedCompilation<SpirvCompilation>,
136 ) -> Result<CompilerBackend<Self::Output>, ShaderReflectError> {
137 SPIRV::from_compilation(compile.compilation)
138 }
139}