зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1560520 - limit the size of WebRender's glyph cache. r=kvark
Differential Revision: https://phabricator.services.mozilla.com/D37982 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
8333f6cdcc
Коммит
ee4cc890cb
|
@ -6,6 +6,7 @@
|
|||
use crate::api::units::DeviceIntPoint;
|
||||
use crate::glyph_rasterizer::{FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
|
||||
use crate::internal_types::FastHashMap;
|
||||
use crate::render_backend::{FrameId, FrameStamp};
|
||||
use crate::render_task::RenderTaskCache;
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use crate::render_task::RenderTaskCacheKey;
|
||||
|
@ -43,29 +44,41 @@ pub enum GlyphCacheEntry {
|
|||
|
||||
impl GlyphCacheEntry {
|
||||
#[cfg(feature = "pathfinder")]
|
||||
fn is_allocated(&self, texture_cache: &TextureCache, render_task_cache: &RenderTaskCache)
|
||||
-> bool {
|
||||
fn get_allocated_size(&self, texture_cache: &TextureCache, render_task_cache: &RenderTaskCache)
|
||||
-> Option<usize> {
|
||||
match *self {
|
||||
GlyphCacheEntry::Cached(ref glyph) => {
|
||||
let render_task_cache_key = &glyph.render_task_cache_key;
|
||||
render_task_cache.cache_item_is_allocated_for_render_task(texture_cache,
|
||||
&render_task_cache_key)
|
||||
render_task_cache.get_allocated_size_for_render_task(texture_cache,
|
||||
&render_task_cache_key)
|
||||
}
|
||||
GlyphCacheEntry::Pending => true,
|
||||
GlyphCacheEntry::Pending => Some(0),
|
||||
// If the cache only has blank glyphs left, just get rid of it.
|
||||
GlyphCacheEntry::Blank => false,
|
||||
GlyphCacheEntry::Blank => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "pathfinder")]
|
||||
fn mark_unused(&self, _: &mut TextureCache) {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "pathfinder"))]
|
||||
fn get_allocated_size(&self, texture_cache: &TextureCache, _: &RenderTaskCache)
|
||||
-> Option<usize> {
|
||||
match *self {
|
||||
GlyphCacheEntry::Cached(ref glyph) => {
|
||||
texture_cache.get_allocated_size(&glyph.texture_cache_handle)
|
||||
}
|
||||
GlyphCacheEntry::Pending => Some(0),
|
||||
// If the cache only has blank glyphs left, just get rid of it.
|
||||
GlyphCacheEntry::Blank => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "pathfinder"))]
|
||||
fn is_allocated(&self, texture_cache: &TextureCache, _: &RenderTaskCache) -> bool {
|
||||
match *self {
|
||||
GlyphCacheEntry::Cached(ref glyph) => {
|
||||
texture_cache.is_allocated(&glyph.texture_cache_handle)
|
||||
}
|
||||
GlyphCacheEntry::Pending => true,
|
||||
// If the cache only has blank glyphs left, just get rid of it.
|
||||
GlyphCacheEntry::Blank => false,
|
||||
fn mark_unused(&self, texture_cache: &mut TextureCache) {
|
||||
if let GlyphCacheEntry::Cached(ref glyph) = *self {
|
||||
texture_cache.mark_unused(&glyph.texture_cache_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,11 +92,53 @@ pub enum CachedGlyphData {
|
|||
Gpu,
|
||||
}
|
||||
|
||||
pub type GlyphKeyCache = ResourceClassCache<GlyphKey, GlyphCacheEntry, EvictionNotice>;
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Default)]
|
||||
pub struct GlyphKeyCacheInfo {
|
||||
eviction_notice: EvictionNotice,
|
||||
last_frame_used: FrameId,
|
||||
bytes_used: usize,
|
||||
}
|
||||
|
||||
pub type GlyphKeyCache = ResourceClassCache<GlyphKey, GlyphCacheEntry, GlyphKeyCacheInfo>;
|
||||
|
||||
impl GlyphKeyCache {
|
||||
const DIRTY: usize = !0;
|
||||
|
||||
pub fn eviction_notice(&self) -> &EvictionNotice {
|
||||
&self.user_data
|
||||
&self.user_data.eviction_notice
|
||||
}
|
||||
|
||||
fn clear_glyphs(&mut self, texture_cache: &mut TextureCache) {
|
||||
for (_, entry) in self.iter() {
|
||||
entry.mark_unused(texture_cache);
|
||||
}
|
||||
self.clear();
|
||||
self.user_data.bytes_used = 0;
|
||||
}
|
||||
|
||||
pub fn add_glyph(&mut self, key: GlyphKey, value: GlyphCacheEntry) {
|
||||
self.insert(key, value);
|
||||
self.user_data.bytes_used = Self::DIRTY;
|
||||
}
|
||||
|
||||
fn clear_evicted(
|
||||
&mut self,
|
||||
texture_cache: &TextureCache,
|
||||
render_task_cache: &RenderTaskCache,
|
||||
) {
|
||||
if self.eviction_notice().check() || self.user_data.bytes_used == Self::DIRTY {
|
||||
// If there are evictions, filter out any glyphs evicted from the
|
||||
// texture cache from the glyph key cache.
|
||||
let mut usage = 0;
|
||||
self.retain(|_, entry| {
|
||||
let size = entry.get_allocated_size(texture_cache, render_task_cache);
|
||||
usage += size.unwrap_or(0);
|
||||
size.is_some()
|
||||
});
|
||||
self.user_data.bytes_used = usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,19 +146,30 @@ impl GlyphKeyCache {
|
|||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct GlyphCache {
|
||||
glyph_key_caches: FastHashMap<FontInstance, GlyphKeyCache>,
|
||||
current_frame: FrameId,
|
||||
bytes_used: usize,
|
||||
max_bytes_used: usize,
|
||||
}
|
||||
|
||||
impl GlyphCache {
|
||||
pub fn new() -> Self {
|
||||
/// The default space usage threshold, in bytes, after which to start pruning away old fonts.
|
||||
pub const DEFAULT_MAX_BYTES_USED: usize = 5 * 1024 * 1024;
|
||||
|
||||
pub fn new(max_bytes_used: usize) -> Self {
|
||||
GlyphCache {
|
||||
glyph_key_caches: FastHashMap::default(),
|
||||
current_frame: Default::default(),
|
||||
bytes_used: 0,
|
||||
max_bytes_used,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_glyph_key_cache_for_font_mut(&mut self, font: FontInstance) -> &mut GlyphKeyCache {
|
||||
self.glyph_key_caches
|
||||
.entry(font)
|
||||
.or_insert_with(GlyphKeyCache::new)
|
||||
let cache = self.glyph_key_caches
|
||||
.entry(font)
|
||||
.or_insert_with(GlyphKeyCache::new);
|
||||
cache.user_data.last_frame_used = self.current_frame;
|
||||
cache
|
||||
}
|
||||
|
||||
pub fn get_glyph_key_cache_for_font(&self, font: &FontInstance) -> &GlyphKeyCache {
|
||||
|
@ -121,7 +187,7 @@ impl GlyphCache {
|
|||
self.glyph_key_caches = FastHashMap::default();
|
||||
}
|
||||
|
||||
pub fn clear_fonts<F>(&mut self, key_fun: F)
|
||||
pub fn clear_fonts<F>(&mut self, texture_cache: &mut TextureCache, key_fun: F)
|
||||
where
|
||||
for<'r> F: Fn(&'r &FontInstance) -> bool,
|
||||
{
|
||||
|
@ -131,45 +197,70 @@ impl GlyphCache {
|
|||
return true;
|
||||
}
|
||||
|
||||
cache.clear();
|
||||
cache.clear_glyphs(texture_cache);
|
||||
false
|
||||
})
|
||||
}
|
||||
|
||||
// Clear out evicted entries from glyph key caches and, if possible,
|
||||
// also remove entirely any subsequently empty glyph key caches.
|
||||
/// Clear out evicted entries from glyph key caches.
|
||||
fn clear_evicted(
|
||||
&mut self,
|
||||
texture_cache: &TextureCache,
|
||||
render_task_cache: &RenderTaskCache,
|
||||
glyph_rasterizer: &mut GlyphRasterizer,
|
||||
) {
|
||||
self.glyph_key_caches.retain(|key, cache| {
|
||||
let mut usage = 0;
|
||||
for cache in self.glyph_key_caches.values_mut() {
|
||||
// Scan for any glyph key caches that have evictions.
|
||||
if cache.eviction_notice().check() {
|
||||
// If there are evictions, filter out any glyphs evicted from the
|
||||
// texture cache from the glyph key cache.
|
||||
let mut keep_cache = false;
|
||||
cache.retain(|_, entry| {
|
||||
let keep_glyph = entry.is_allocated(texture_cache, render_task_cache);
|
||||
keep_cache |= keep_glyph;
|
||||
keep_glyph
|
||||
});
|
||||
if !keep_cache {
|
||||
glyph_rasterizer.delete_font_instance(key);
|
||||
}
|
||||
// Only keep the glyph key cache if it still has valid glyphs.
|
||||
keep_cache
|
||||
cache.clear_evicted(texture_cache, render_task_cache);
|
||||
usage += cache.user_data.bytes_used;
|
||||
}
|
||||
self.bytes_used = usage;
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Check the total space usage of the glyph cache. If it exceeds the maximum usage threshold,
|
||||
/// then start clearing the oldest glyphs until below the threshold.
|
||||
fn prune_excess_usage(&mut self, texture_cache: &mut TextureCache) {
|
||||
if self.bytes_used < self.max_bytes_used {
|
||||
return;
|
||||
}
|
||||
// Usage is above the threshold. Get a last-recently-used ordered list of caches to clear.
|
||||
let mut caches: Vec<_> = self.glyph_key_caches.values_mut().collect();
|
||||
caches.sort_unstable_by(|a, b| {
|
||||
a.user_data.last_frame_used.cmp(&b.user_data.last_frame_used)
|
||||
});
|
||||
// Clear out the oldest caches until below the threshold.
|
||||
for cache in caches {
|
||||
self.bytes_used -= cache.user_data.bytes_used;
|
||||
cache.clear_glyphs(texture_cache);
|
||||
if self.bytes_used < self.max_bytes_used {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn begin_frame(&mut self,
|
||||
texture_cache: &TextureCache,
|
||||
stamp: FrameStamp,
|
||||
texture_cache: &mut TextureCache,
|
||||
render_task_cache: &RenderTaskCache,
|
||||
glyph_rasterizer: &mut GlyphRasterizer) {
|
||||
self.clear_evicted(texture_cache, render_task_cache, glyph_rasterizer);
|
||||
self.current_frame = stamp.frame_id();
|
||||
self.clear_evicted(texture_cache, render_task_cache);
|
||||
self.prune_excess_usage(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -863,7 +863,7 @@ mod test_glyph_rasterizer {
|
|||
.build();
|
||||
let workers = Arc::new(worker.unwrap());
|
||||
let mut glyph_rasterizer = GlyphRasterizer::new(workers).unwrap();
|
||||
let mut glyph_cache = GlyphCache::new();
|
||||
let mut glyph_cache = GlyphCache::new(GlyphCache::DEFAULT_MAX_BYTES_USED);
|
||||
let mut gpu_cache = GpuCache::new_for_testing();
|
||||
let mut texture_cache = TextureCache::new_for_testing(2048, 1024);
|
||||
let mut render_task_cache = RenderTaskCache::new();
|
||||
|
|
|
@ -20,7 +20,6 @@ use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction};
|
|||
use crate::gpu_cache::GpuCache;
|
||||
use crate::render_task::{RenderTaskGraph, RenderTaskCache};
|
||||
use crate::profiler::TextureCacheProfileCounters;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
impl FontContexts {
|
||||
/// Get access to the font context associated to the current thread.
|
||||
|
@ -57,32 +56,23 @@ impl GlyphRasterizer {
|
|||
|
||||
// select glyphs that have not been requested yet.
|
||||
for key in glyph_keys {
|
||||
match glyph_key_cache.entry(key.clone()) {
|
||||
Entry::Occupied(entry) => {
|
||||
let value = entry.into_mut();
|
||||
match *value {
|
||||
GlyphCacheEntry::Cached(ref glyph) => {
|
||||
// Skip the glyph if it is already has a valid texture cache handle.
|
||||
if !texture_cache.request(&glyph.texture_cache_handle, gpu_cache) {
|
||||
continue;
|
||||
}
|
||||
if let Some(entry) = glyph_key_cache.try_get(key) {
|
||||
match entry {
|
||||
GlyphCacheEntry::Cached(ref glyph) => {
|
||||
// Skip the glyph if it is already has a valid texture cache handle.
|
||||
if !texture_cache.request(&glyph.texture_cache_handle, gpu_cache) {
|
||||
continue;
|
||||
}
|
||||
// Otherwise, skip the entry if it is blank or pending.
|
||||
GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => continue,
|
||||
// This case gets hit when we already rasterized the glyph, but the
|
||||
// glyph has been evicted from the texture cache. Just force it to
|
||||
// pending so it gets rematerialized.
|
||||
}
|
||||
|
||||
// This case gets hit when we already rasterized the glyph, but the
|
||||
// glyph has been evicted from the texture cache. Just force it to
|
||||
// pending so it gets rematerialized.
|
||||
*value = GlyphCacheEntry::Pending;
|
||||
new_glyphs.push((*key).clone());
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
// This is the first time we've seen the glyph, so mark it as pending.
|
||||
entry.insert(GlyphCacheEntry::Pending);
|
||||
new_glyphs.push((*key).clone());
|
||||
// Otherwise, skip the entry if it is blank or pending.
|
||||
GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => continue,
|
||||
}
|
||||
}
|
||||
new_glyphs.push(key.clone());
|
||||
glyph_key_cache.add_glyph(key.clone(), GlyphCacheEntry::Pending);
|
||||
}
|
||||
|
||||
if new_glyphs.is_empty() {
|
||||
|
@ -197,7 +187,7 @@ impl GlyphRasterizer {
|
|||
})
|
||||
}
|
||||
};
|
||||
glyph_key_cache.insert(key, glyph_info);
|
||||
glyph_key_cache.add_glyph(key, glyph_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ use std::sync::{Arc, Mutex, MutexGuard};
|
|||
use crate::glyph_rasterizer::AddFont;
|
||||
use crate::internal_types::ResourceCacheError;
|
||||
use crate::glyph_cache::{GlyphCache, GlyphCacheEntry, CachedGlyphInfo};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::f32;
|
||||
use crate::glyph_rasterizer::{FontInstance, GlyphRasterizer, GlyphFormat, GlyphKey, FontContexts};
|
||||
use crate::texture_cache::TextureCache;
|
||||
|
@ -169,20 +168,9 @@ impl GlyphRasterizer {
|
|||
// select glyphs that have not been requested yet.
|
||||
for glyph_key in glyph_keys {
|
||||
let mut cached_glyph_info = None;
|
||||
match glyph_key_cache.entry(glyph_key.clone()) {
|
||||
Entry::Occupied(entry) => {
|
||||
let value = entry.into_mut();
|
||||
match *value {
|
||||
GlyphCacheEntry::Cached(ref glyph_info) => {
|
||||
cached_glyph_info = Some(glyph_info.clone())
|
||||
}
|
||||
GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => {}
|
||||
}
|
||||
}
|
||||
Entry::Vacant(_) => {}
|
||||
}
|
||||
|
||||
if cached_glyph_info.is_none() {
|
||||
if let Some(GlyphCacheEntry::Cached(ref info)) = glyph_key_cache.try_get(glyph_key) {
|
||||
cached_glyph_info = Some(info.clone());
|
||||
} else {
|
||||
let pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
|
||||
|
||||
let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
|
||||
|
@ -234,7 +222,7 @@ impl GlyphRasterizer {
|
|||
None => GlyphCacheEntry::Blank,
|
||||
};
|
||||
|
||||
glyph_key_cache.insert(glyph_key.clone(), handle);
|
||||
glyph_key_cache.add_glyph(glyph_key.clone(), handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,12 @@ impl FrameId {
|
|||
pub const INVALID: FrameId = FrameId(0);
|
||||
}
|
||||
|
||||
impl Default for FrameId {
|
||||
fn default() -> Self {
|
||||
FrameId::INVALID
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Add<usize> for FrameId {
|
||||
type Output = Self;
|
||||
fn add(self, other: usize) -> FrameId {
|
||||
|
|
|
@ -2136,13 +2136,13 @@ impl RenderTaskCache {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn cache_item_is_allocated_for_render_task(&self,
|
||||
texture_cache: &TextureCache,
|
||||
key: &RenderTaskCacheKey)
|
||||
-> bool {
|
||||
pub fn get_allocated_size_for_render_task(&self,
|
||||
texture_cache: &TextureCache,
|
||||
key: &RenderTaskCacheKey)
|
||||
-> Option<usize> {
|
||||
let handle = self.map.get(key).unwrap();
|
||||
let cache_entry = self.cache_entries.get(handle);
|
||||
texture_cache.is_allocated(&cache_entry.handle)
|
||||
texture_cache.get_allocated_size(&cache_entry.handle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ use crate::device::query::GpuTimer;
|
|||
use euclid::{rect, Transform3D, TypedScale};
|
||||
use crate::frame_builder::{ChasePrimitive, FrameBuilderConfig};
|
||||
use gleam::gl;
|
||||
use crate::glyph_cache::GlyphCache;
|
||||
use crate::glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
|
||||
use crate::gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
|
||||
use crate::gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd};
|
||||
|
@ -2082,6 +2083,7 @@ impl Renderer {
|
|||
});
|
||||
let sampler = options.sampler;
|
||||
let namespace_alloc_by_client = options.namespace_alloc_by_client;
|
||||
let max_glyph_cache_size = options.max_glyph_cache_size.unwrap_or(GlyphCache::DEFAULT_MAX_BYTES_USED);
|
||||
|
||||
let blob_image_handler = options.blob_image_handler.take();
|
||||
let thread_listener_for_render_backend = thread_listener.clone();
|
||||
|
@ -2161,9 +2163,12 @@ impl Renderer {
|
|||
start_size,
|
||||
);
|
||||
|
||||
let glyph_cache = GlyphCache::new(max_glyph_cache_size);
|
||||
|
||||
let resource_cache = ResourceCache::new(
|
||||
texture_cache,
|
||||
glyph_rasterizer,
|
||||
glyph_cache,
|
||||
blob_image_handler,
|
||||
);
|
||||
|
||||
|
@ -5478,6 +5483,7 @@ pub struct RendererOptions {
|
|||
pub clear_color: Option<ColorF>,
|
||||
pub enable_clear_scissor: bool,
|
||||
pub max_texture_size: Option<i32>,
|
||||
pub max_glyph_cache_size: Option<usize>,
|
||||
pub scatter_gpu_cache_updates: bool,
|
||||
pub upload_method: UploadMethod,
|
||||
pub workers: Option<Arc<ThreadPool>>,
|
||||
|
@ -5532,6 +5538,7 @@ impl Default for RendererOptions {
|
|||
clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
|
||||
enable_clear_scissor: true,
|
||||
max_texture_size: None,
|
||||
max_glyph_cache_size: None,
|
||||
// Scattered GPU cache updates haven't met a test that would show their superiority yet.
|
||||
scatter_gpu_cache_updates: false,
|
||||
// This is best as `Immediate` on Angle, or `Pixelbuffer(Dynamic)` on GL,
|
||||
|
|
|
@ -33,7 +33,7 @@ use crate::render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId};
|
|||
use crate::render_task::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle, RenderTaskGraph};
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
|
||||
use std::collections::hash_map::IterMut;
|
||||
use std::collections::hash_map::{Iter, IterMut};
|
||||
use std::collections::VecDeque;
|
||||
use std::{cmp, mem};
|
||||
use std::fmt::Debug;
|
||||
|
@ -273,10 +273,18 @@ where
|
|||
self.resources.entry(key)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
self.resources.iter()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||
self.resources.iter_mut()
|
||||
}
|
||||
|
||||
pub fn is_empty(&mut self) -> bool {
|
||||
self.resources.is_empty()
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.resources.clear();
|
||||
}
|
||||
|
@ -491,10 +499,11 @@ impl ResourceCache {
|
|||
pub fn new(
|
||||
texture_cache: TextureCache,
|
||||
glyph_rasterizer: GlyphRasterizer,
|
||||
cached_glyphs: GlyphCache,
|
||||
blob_image_handler: Option<Box<dyn BlobImageHandler>>,
|
||||
) -> Self {
|
||||
ResourceCache {
|
||||
cached_glyphs: GlyphCache::new(),
|
||||
cached_glyphs,
|
||||
cached_images: ResourceClassCache::new(),
|
||||
cached_render_tasks: RenderTaskCache::new(),
|
||||
resources: Resources::default(),
|
||||
|
@ -781,7 +790,7 @@ impl ResourceCache {
|
|||
self.glyph_rasterizer.delete_font(font_key);
|
||||
self.resources.font_templates.remove(&font_key);
|
||||
self.cached_glyphs
|
||||
.clear_fonts(|font| font.font_key == font_key);
|
||||
.clear_fonts(&mut self.texture_cache, |font| font.font_key == font_key);
|
||||
if let Some(ref mut r) = self.blob_image_handler {
|
||||
r.delete_font(font_key);
|
||||
}
|
||||
|
@ -1604,7 +1613,12 @@ impl ResourceCache {
|
|||
debug_assert_eq!(self.state, State::Idle);
|
||||
self.state = State::AddResources;
|
||||
self.texture_cache.begin_frame(stamp);
|
||||
self.cached_glyphs.begin_frame(&self.texture_cache, &self.cached_render_tasks, &mut self.glyph_rasterizer);
|
||||
self.cached_glyphs.begin_frame(
|
||||
stamp,
|
||||
&mut self.texture_cache,
|
||||
&self.cached_render_tasks,
|
||||
&mut self.glyph_rasterizer,
|
||||
);
|
||||
self.cached_render_tasks.begin_frame(&mut self.texture_cache);
|
||||
self.current_frame_id = stamp.frame_id();
|
||||
self.active_image_keys.clear();
|
||||
|
@ -1842,7 +1856,7 @@ impl ResourceCache {
|
|||
.font_templates
|
||||
.retain(|key, _| key.0 != namespace);
|
||||
self.cached_glyphs
|
||||
.clear_fonts(|font| font.font_key.0 == namespace);
|
||||
.clear_fonts(&mut self.texture_cache, |font| font.font_key.0 == namespace);
|
||||
|
||||
if let Some(ref mut r) = self.blob_image_handler {
|
||||
r.clear_namespace(namespace);
|
||||
|
|
|
@ -916,6 +916,14 @@ impl TextureCache {
|
|||
self.entries.get_opt(handle).is_some()
|
||||
}
|
||||
|
||||
// Return the allocated size of the texture handle's associated data,
|
||||
// or otherwise indicate the handle is invalid.
|
||||
pub fn get_allocated_size(&self, handle: &TextureCacheHandle) -> Option<usize> {
|
||||
self.entries.get_opt(handle).map(|entry| {
|
||||
(entry.format.bytes_per_pixel() * entry.size.area()) as usize
|
||||
})
|
||||
}
|
||||
|
||||
// Retrieve the details of an item in the cache. This is used
|
||||
// during batch creation to provide the resource rect address
|
||||
// to the shaders and texture ID to the batching logic.
|
||||
|
|
Загрузка…
Ссылка в новой задаче