//! Cache helpers for `ShaderCompilation` objects to cache compiled SPIRV. use librashader_preprocess::ShaderSource; #[cfg(all(target_os = "windows", feature = "d3d"))] use librashader_reflect::back::targets::DXIL; use librashader_reflect::back::targets::{GLSL, HLSL, SPIRV}; use librashader_reflect::back::{CompilerBackend, FromCompilation}; use librashader_reflect::error::{ShaderCompileError, ShaderReflectError}; use librashader_reflect::front::{ Glslang, ShaderInputCompiler, ShaderReflectObject, SpirvCompilation, }; pub struct CachedCompilation { compilation: T, } impl ShaderReflectObject for CachedCompilation { type Compiler = T::Compiler; } impl serde::Deserialize<'de> + serde::Serialize + Clone> ShaderInputCompiler> for Glslang where Glslang: ShaderInputCompiler, { fn compile(source: &ShaderSource) -> Result, ShaderCompileError> { let cache = crate::cache::internal::get_cache(); let Ok(cache) = cache else { return Ok(CachedCompilation { compilation: Glslang::compile(source)?, }); }; let key = { let mut hasher = blake3::Hasher::new(); hasher.update(source.vertex.as_bytes()); hasher.update(source.fragment.as_bytes()); let hash = hasher.finalize(); hash }; let compilation = 'cached: { if let Ok(Some(cached)) = crate::cache::internal::get_blob(&cache, "spirv", key.as_bytes()) { let decoded = bincode::serde::decode_from_slice(&cached, bincode::config::standard()) .map(|(compilation, _)| CachedCompilation { compilation }) .ok(); if let Some(compilation) = decoded { break 'cached compilation; } } CachedCompilation { compilation: Glslang::compile(source)?, } }; if let Ok(updated) = bincode::serde::encode_to_vec(&compilation.compilation, bincode::config::standard()) { let Ok(()) = crate::cache::internal::set_blob(&cache, "spirv", key.as_bytes(), &updated) else { return Ok(compilation); }; } Ok(compilation) } } #[cfg(all(target_os = "windows", feature = "d3d"))] impl FromCompilation, T> for DXIL where DXIL: FromCompilation, { type Target = >::Target; type Options = >::Options; type Context = >::Context; type Output = >::Output; fn from_compilation( compile: CachedCompilation, ) -> Result, ShaderReflectError> { DXIL::from_compilation(compile.compilation) } } impl FromCompilation, T> for HLSL where HLSL: FromCompilation, { type Target = >::Target; type Options = >::Options; type Context = >::Context; type Output = >::Output; fn from_compilation( compile: CachedCompilation, ) -> Result, ShaderReflectError> { HLSL::from_compilation(compile.compilation) } } impl FromCompilation, T> for GLSL where GLSL: FromCompilation, { type Target = >::Target; type Options = >::Options; type Context = >::Context; type Output = >::Output; fn from_compilation( compile: CachedCompilation, ) -> Result, ShaderReflectError> { GLSL::from_compilation(compile.compilation) } } impl FromCompilation, T> for SPIRV where SPIRV: FromCompilation, { type Target = >::Target; type Options = >::Options; type Context = >::Context; type Output = >::Output; fn from_compilation( compile: CachedCompilation, ) -> Result, ShaderReflectError> { SPIRV::from_compilation(compile.compilation) } }