1use api::{FontKey, FontInstanceKey, IdNamespace};
6use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
7use crate::internal_types::{FrameId, FrameStamp, FastHashMap};
8use crate::resource_cache::ResourceClassCache;
9use std::sync::Arc;
10use crate::texture_cache::{EvictionNotice, TextureCache};
11use crate::texture_cache::TextureCacheHandle;
12
13#[cfg_attr(feature = "capture", derive(Serialize))]
14#[cfg_attr(feature = "replay", derive(Deserialize))]
15#[derive(Clone, Debug)]
16pub struct CachedGlyphInfo {
17 pub format: GlyphFormat,
18 pub texture_cache_handle: TextureCacheHandle,
19}
20
21#[cfg_attr(feature = "capture", derive(Serialize))]
22#[cfg_attr(feature = "replay", derive(Deserialize))]
23pub enum GlyphCacheEntry {
24 Cached(CachedGlyphInfo),
26 Blank,
28 #[allow(dead_code)]
31 Pending,
32}
33
34impl GlyphCacheEntry {
35 fn has_been_evicted(&self, texture_cache: &TextureCache) -> bool {
36 match *self {
37 GlyphCacheEntry::Cached(ref glyph) => {
38 !texture_cache.is_allocated(&glyph.texture_cache_handle)
39 }
40 GlyphCacheEntry::Pending | GlyphCacheEntry::Blank => false,
41 }
42 }
43}
44
45#[allow(dead_code)]
46#[cfg_attr(feature = "capture", derive(Serialize))]
47#[cfg_attr(feature = "replay", derive(Deserialize))]
48#[derive(Clone)]
49pub enum CachedGlyphData {
50 Memory(Arc<Vec<u8>>),
51 Gpu,
52}
53
54#[cfg_attr(feature = "capture", derive(Serialize))]
55#[cfg_attr(feature = "replay", derive(Deserialize))]
56#[derive(Default)]
57pub struct GlyphKeyCacheInfo {
58 eviction_notice: EvictionNotice,
59 #[cfg(debug_assertions)]
60 #[allow(dead_code)]
61 #[cfg_attr(feature = "replay", serde(default))]
62 last_frame_used: FrameId,
63}
64
65pub type GlyphKeyCache = ResourceClassCache<GlyphKey, GlyphCacheEntry, GlyphKeyCacheInfo>;
66
67impl GlyphKeyCache {
68 pub fn eviction_notice(&self) -> &EvictionNotice {
69 &self.user_data.eviction_notice
70 }
71
72 fn clear_glyphs(&mut self) {
73 self.clear();
74 }
75
76 pub fn add_glyph(&mut self, key: GlyphKey, value: GlyphCacheEntry) {
77 self.insert(key, value);
78 }
79
80 fn clear_evicted(&mut self, texture_cache: &TextureCache) {
81 if self.eviction_notice().check() {
82 self.retain(|_, entry| !entry.has_been_evicted(texture_cache));
85 }
86 }
87}
88
89#[cfg_attr(feature = "capture", derive(Serialize))]
90#[cfg_attr(feature = "replay", derive(Deserialize))]
91pub struct GlyphCache {
92 glyph_key_caches: FastHashMap<FontInstance, GlyphKeyCache>,
93 current_frame: FrameId,
94}
95
96impl GlyphCache {
97 pub fn new() -> Self {
98 GlyphCache {
99 glyph_key_caches: FastHashMap::default(),
100 current_frame: Default::default(),
101 }
102 }
103
104 pub fn insert_glyph_key_cache_for_font(&mut self, font: &FontInstance) -> &mut GlyphKeyCache {
105 let cache = self.glyph_key_caches
106 .entry(font.clone())
107 .or_insert_with(GlyphKeyCache::new);
108 #[cfg(debug_assertions)]
109 {
110 cache.user_data.last_frame_used = self.current_frame;
111 }
112 cache
113 }
114
115 pub fn get_glyph_key_cache_for_font_mut(&mut self, font: &FontInstance) -> &mut GlyphKeyCache {
116 self.glyph_key_caches
117 .get_mut(font)
118 .expect("BUG: Unable to find glyph key cache!")
119 }
120
121 pub fn get_glyph_key_cache_for_font(&self, font: &FontInstance) -> &GlyphKeyCache {
122 self.glyph_key_caches
123 .get(font)
124 .expect("BUG: Unable to find glyph key cache!")
125 }
126
127 pub fn clear(&mut self) {
128 for (_, glyph_key_cache) in &mut self.glyph_key_caches {
129 glyph_key_cache.clear()
130 }
131 self.glyph_key_caches = FastHashMap::default();
134 }
135
136 pub fn delete_font_instances(
137 &mut self,
138 instance_keys: &[FontInstanceKey],
139 glyph_rasterizer: &mut GlyphRasterizer,
140 ) {
141 self.glyph_key_caches.retain(|k, cache| {
142 if instance_keys.contains(&k.instance_key) {
143 cache.clear_glyphs();
144 glyph_rasterizer.delete_font_instance(k);
145 false
146 } else {
147 true
148 }
149 });
150 }
151
152 pub fn delete_fonts(&mut self, font_keys: &[FontKey]) {
153 self.glyph_key_caches.retain(|k, cache| {
154 if font_keys.contains(&k.font_key) {
155 cache.clear_glyphs();
156 false
157 } else {
158 true
159 }
160 });
161 }
162
163 pub fn clear_namespace(&mut self, namespace: IdNamespace) {
164 self.glyph_key_caches.retain(|k, cache| {
165 if k.font_key.0 == namespace {
166 cache.clear_glyphs();
167 false
168 } else {
169 true
170 }
171 });
172 }
173
174 fn clear_evicted(&mut self, texture_cache: &TextureCache) {
176 for cache in self.glyph_key_caches.values_mut() {
177 cache.clear_evicted(texture_cache);
179 }
180 }
181
182 fn clear_empty_caches(&mut self, glyph_rasterizer: &mut GlyphRasterizer) {
184 self.glyph_key_caches.retain(|key, cache| {
185 if cache.is_empty() {
187 glyph_rasterizer.delete_font_instance(key);
188 false
189 } else {
190 true
191 }
192 });
193 }
194
195 pub fn begin_frame(
196 &mut self,
197 stamp: FrameStamp,
198 texture_cache: &mut TextureCache,
199 glyph_rasterizer: &mut GlyphRasterizer,
200 ) {
201 profile_scope!("begin_frame");
202 self.current_frame = stamp.frame_id();
203 self.clear_evicted(texture_cache);
204 self.clear_empty_caches(glyph_rasterizer);
207 }
208}