//! Cache helpers for `ShaderCompilation` objects to cache compiled SPIRV. use librashader_preprocess::ShaderSource; use librashader_reflect::back::targets::{DXIL, GLSL, HLSL, SPIRV}; use librashader_reflect::back::{CompilerBackend, FromCompilation}; use librashader_reflect::error::{ShaderCompileError, ShaderReflectError}; use librashader_reflect::front::{GlslangCompilation, ShaderCompilation}; pub struct CachedCompilation { compilation: T, } impl serde::Deserialize<'de> + serde::Serialize + Clone> ShaderCompilation for CachedCompilation { fn compile(source: &ShaderSource) -> Result { let cache = crate::cache::internal::get_cache(); let Ok(cache) = cache else { return Ok(CachedCompilation { compilation: T::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(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: T::compile(source)?, } }; if let Ok(updated) = bincode::serde::encode_to_vec(&compilation.compilation, bincode::config::standard()) { crate::cache::internal::set_blob(&cache, "spirv", key.as_bytes(), &updated) } Ok(compilation) } } #[cfg(all(target_os = "windows", feature = "d3d"))] impl FromCompilation> for DXIL { 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> for HLSL { 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> for GLSL { 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> for SPIRV { type Target = >::Target; type Options = >::Options; type Context = >::Context; type Output = >::Output; fn from_compilation( compile: CachedCompilation, ) -> Result, ShaderReflectError> { SPIRV::from_compilation(compile.compilation) } }