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