oxigdal_gpu_advanced/shader_compiler/
cache.rs1use super::CompiledShader;
4use blake3::Hash;
5use lru::LruCache;
6use parking_lot::Mutex;
7use std::num::NonZeroUsize;
8
9const DEFAULT_CACHE_CAPACITY: NonZeroUsize = match NonZeroUsize::new(1000) {
11 Some(v) => v,
12 None => unreachable!(),
13};
14
15pub struct ShaderCache {
17 cache: Mutex<LruCache<Hash, CompiledShader>>,
19 hits: Mutex<u64>,
21 misses: Mutex<u64>,
23}
24
25impl ShaderCache {
26 pub fn new(capacity: usize) -> Self {
28 let cap = NonZeroUsize::new(capacity).unwrap_or(DEFAULT_CACHE_CAPACITY);
29 Self {
30 cache: Mutex::new(LruCache::new(cap)),
31 hits: Mutex::new(0),
32 misses: Mutex::new(0),
33 }
34 }
35
36 pub fn insert(&self, hash: Hash, shader: CompiledShader) {
38 let mut cache = self.cache.lock();
39 cache.put(hash, shader);
40 }
41
42 pub fn get(&self, hash: &Hash) -> Option<CompiledShader> {
44 let mut cache = self.cache.lock();
45 if let Some(shader) = cache.get(hash) {
46 *self.hits.lock() += 1;
47 Some(shader.clone())
48 } else {
49 *self.misses.lock() += 1;
50 None
51 }
52 }
53
54 pub fn contains(&self, hash: &Hash) -> bool {
56 let cache = self.cache.lock();
57 cache.contains(hash)
58 }
59
60 pub fn clear(&self) {
62 let mut cache = self.cache.lock();
63 cache.clear();
64 }
65
66 pub fn len(&self) -> usize {
68 let cache = self.cache.lock();
69 cache.len()
70 }
71
72 pub fn is_empty(&self) -> bool {
74 self.len() == 0
75 }
76
77 pub fn get_stats(&self) -> CacheStats {
79 let hits = *self.hits.lock();
80 let misses = *self.misses.lock();
81 let size = self.len();
82
83 CacheStats {
84 hits,
85 misses,
86 size,
87 hit_rate: if hits + misses > 0 {
88 (hits as f64) / ((hits + misses) as f64)
89 } else {
90 0.0
91 },
92 }
93 }
94
95 pub fn reset_stats(&self) {
97 *self.hits.lock() = 0;
98 *self.misses.lock() = 0;
99 }
100}
101
102#[derive(Debug, Clone)]
104pub struct CacheStats {
105 pub hits: u64,
107 pub misses: u64,
109 pub size: usize,
111 pub hit_rate: f64,
113}
114
115impl CacheStats {
116 pub fn print(&self) {
118 println!("\nShader Cache Statistics:");
119 println!(" Hits: {}", self.hits);
120 println!(" Misses: {}", self.misses);
121 println!(" Hit rate: {:.1}%", self.hit_rate * 100.0);
122 println!(" Cache size: {}", self.size);
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_cache_creation() {
132 let cache = ShaderCache::new(100);
133 assert_eq!(cache.len(), 0);
134 assert!(cache.is_empty());
135 }
136
137 #[test]
138 fn test_cache_stats() {
139 let cache = ShaderCache::new(100);
140 let stats = cache.get_stats();
141 assert_eq!(stats.hits, 0);
142 assert_eq!(stats.misses, 0);
143 assert_eq!(stats.hit_rate, 0.0);
144 }
145}