summaryrefslogtreecommitdiffstats
path: root/gfx/wr/webrender/src/glyph_cache.rs
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/wr/webrender/src/glyph_cache.rs')
-rw-r--r--gfx/wr/webrender/src/glyph_cache.rs208
1 files changed, 208 insertions, 0 deletions
diff --git a/gfx/wr/webrender/src/glyph_cache.rs b/gfx/wr/webrender/src/glyph_cache.rs
new file mode 100644
index 0000000000..0f895e3212
--- /dev/null
+++ b/gfx/wr/webrender/src/glyph_cache.rs
@@ -0,0 +1,208 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use api::{FontKey, FontInstanceKey, IdNamespace};
+use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
+use crate::internal_types::{FrameId, FrameStamp, FastHashMap};
+use crate::resource_cache::ResourceClassCache;
+use std::sync::Arc;
+use crate::texture_cache::{EvictionNotice, TextureCache};
+use crate::texture_cache::TextureCacheHandle;
+
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(Clone, Debug)]
+pub struct CachedGlyphInfo {
+ pub format: GlyphFormat,
+ pub texture_cache_handle: TextureCacheHandle,
+}
+
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub enum GlyphCacheEntry {
+ // A glyph that has been successfully rasterized.
+ Cached(CachedGlyphInfo),
+ // A glyph that should not be rasterized (i.e. a space).
+ Blank,
+ // A glyph that has been submitted to the font backend for rasterization,
+ // but is still pending a result.
+ #[allow(dead_code)]
+ Pending,
+}
+
+impl GlyphCacheEntry {
+ fn has_been_evicted(&self, texture_cache: &TextureCache) -> bool {
+ match *self {
+ GlyphCacheEntry::Cached(ref glyph) => {
+ !texture_cache.is_allocated(&glyph.texture_cache_handle)
+ }
+ GlyphCacheEntry::Pending | GlyphCacheEntry::Blank => false,
+ }
+ }
+}
+
+#[allow(dead_code)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(Clone)]
+pub enum CachedGlyphData {
+ Memory(Arc<Vec<u8>>),
+ Gpu,
+}
+
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(Default)]
+pub struct GlyphKeyCacheInfo {
+ eviction_notice: EvictionNotice,
+ #[cfg(debug_assertions)]
+ #[allow(dead_code)]
+ #[cfg_attr(feature = "replay", serde(default))]
+ last_frame_used: FrameId,
+}
+
+pub type GlyphKeyCache = ResourceClassCache<GlyphKey, GlyphCacheEntry, GlyphKeyCacheInfo>;
+
+impl GlyphKeyCache {
+ pub fn eviction_notice(&self) -> &EvictionNotice {
+ &self.user_data.eviction_notice
+ }
+
+ fn clear_glyphs(&mut self) {
+ self.clear();
+ }
+
+ pub fn add_glyph(&mut self, key: GlyphKey, value: GlyphCacheEntry) {
+ self.insert(key, value);
+ }
+
+ fn clear_evicted(&mut self, texture_cache: &TextureCache) {
+ if self.eviction_notice().check() {
+ // If there are evictions, filter out any glyphs evicted from the
+ // texture cache from the glyph key cache.
+ self.retain(|_, entry| !entry.has_been_evicted(texture_cache));
+ }
+ }
+}
+
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct GlyphCache {
+ glyph_key_caches: FastHashMap<FontInstance, GlyphKeyCache>,
+ current_frame: FrameId,
+}
+
+impl GlyphCache {
+ pub fn new() -> Self {
+ GlyphCache {
+ glyph_key_caches: FastHashMap::default(),
+ current_frame: Default::default(),
+ }
+ }
+
+ pub fn insert_glyph_key_cache_for_font(&mut self, font: &FontInstance) -> &mut GlyphKeyCache {
+ let cache = self.glyph_key_caches
+ .entry(font.clone())
+ .or_insert_with(GlyphKeyCache::new);
+ #[cfg(debug_assertions)]
+ {
+ cache.user_data.last_frame_used = self.current_frame;
+ }
+ cache
+ }
+
+ pub fn get_glyph_key_cache_for_font_mut(&mut self, font: &FontInstance) -> &mut GlyphKeyCache {
+ self.glyph_key_caches
+ .get_mut(font)
+ .expect("BUG: Unable to find glyph key cache!")
+ }
+
+ pub fn get_glyph_key_cache_for_font(&self, font: &FontInstance) -> &GlyphKeyCache {
+ self.glyph_key_caches
+ .get(font)
+ .expect("BUG: Unable to find glyph key cache!")
+ }
+
+ pub fn clear(&mut self) {
+ for (_, glyph_key_cache) in &mut self.glyph_key_caches {
+ glyph_key_cache.clear()
+ }
+ // We use this in on_memory_pressure where retaining memory allocations
+ // isn't desirable, so we completely remove the hash map instead of clearing it.
+ self.glyph_key_caches = FastHashMap::default();
+ }
+
+ pub fn delete_font_instances(
+ &mut self,
+ instance_keys: &[FontInstanceKey],
+ glyph_rasterizer: &mut GlyphRasterizer,
+ ) {
+ self.glyph_key_caches.retain(|k, cache| {
+ if instance_keys.contains(&k.instance_key) {
+ cache.clear_glyphs();
+ glyph_rasterizer.delete_font_instance(k);
+ false
+ } else {
+ true
+ }
+ });
+ }
+
+ pub fn delete_fonts(&mut self, font_keys: &[FontKey]) {
+ self.glyph_key_caches.retain(|k, cache| {
+ if font_keys.contains(&k.font_key) {
+ cache.clear_glyphs();
+ false
+ } else {
+ true
+ }
+ });
+ }
+
+ pub fn clear_namespace(&mut self, namespace: IdNamespace) {
+ self.glyph_key_caches.retain(|k, cache| {
+ if k.font_key.0 == namespace {
+ cache.clear_glyphs();
+ false
+ } else {
+ true
+ }
+ });
+ }
+
+ /// Clear out evicted entries from glyph key caches.
+ fn clear_evicted(&mut self, texture_cache: &TextureCache) {
+ for cache in self.glyph_key_caches.values_mut() {
+ // Scan for any glyph key caches that have evictions.
+ cache.clear_evicted(texture_cache);
+ }
+ }
+
+ /// If possible, remove entirely any empty glyph key caches.
+ fn clear_empty_caches(&mut self, glyph_rasterizer: &mut GlyphRasterizer) {
+ self.glyph_key_caches.retain(|key, cache| {
+ // Discard the glyph key cache if it has no valid glyphs.
+ if cache.is_empty() {
+ glyph_rasterizer.delete_font_instance(key);
+ false
+ } else {
+ true
+ }
+ });
+ }
+
+ pub fn begin_frame(
+ &mut self,
+ stamp: FrameStamp,
+ texture_cache: &mut TextureCache,
+ glyph_rasterizer: &mut GlyphRasterizer,
+ ) {
+ profile_scope!("begin_frame");
+ self.current_frame = stamp.frame_id();
+ self.clear_evicted(texture_cache);
+ // Clearing evicted glyphs and pruning excess usage might have produced empty caches,
+ // so get rid of them if possible.
+ self.clear_empty_caches(glyph_rasterizer);
+ }
+}